Loading

Uploading and the Thingiverse API

Uploading files through a web browser can be tricky, and doing it through a RESTful API which relies on a 3rd party storage service is downright confusing. That's why we put together this quick guide to make it a little easier for you.

The basic mechanism is as follows:

  1. Create or load the item that you'll be attaching the file(s) to (ie: Thing, copy, etc).
  2. Submit a POST to that item's files endpoint (ie: /things/#{id}/files).
  3. Use the parameters returned to upload to our Amazon S3 storage using an HTTP POST with multipart/form-data encoding.

See, it's not so bad. Now let's walk through the steps in detail. We'll show the full HTTP transaction in the sample requests and responses in this guide so you can see all the gory bits.

Step 1. Create or load the item that you'll be attaching to.

If you're adding files to a new item (Thing, copy, etc) you'll need to create that first using the normal API endpoints defined in our REST API Reference. If the item already exists make sure you can access it by loading it first.

Request

          POST /things HTTP/1.1
          Authorization: Bearer e72e16c7e42f292c6912e7710c838347ae178b4a
          Host: api.thingiverse.com
          Content-Type: application/json; charset=utf-8
          Content-Length: 25

          {
            "name":"Super Cool Thing",
            "category":"Art",
            "tags":["foo","bar","baz"],
            "description":"This is a test thing",
            "instructions":"Print and enjoy",
            "is_wip":true,
            "license":"cc"
          }
        

Response

          HTTP/1.1 200 OK
          Date: Fri, 28 Dec 2012 01:50:33 GMT
          Server: Apache
          X-RateLimit-Remaining: 299
          Cache-Control: max-age=87600, min-fresh=300
          Expires: Sat, 29 Dec 2012 16:22:06 -0500
          Vary: Authorization,Accept-Encoding
          Content-Length: 1260
          Connection: close
          Content-Type: application/json; charset=utf-8

          {
            "id":38514,
            "name":"Super Cool Thing",
            "thumbnail":"https://www.thingiverse.com/img/default/rendering_thumb_medium.jpg"",
            "url":"https://www.thingiverse.com/thing:38514",
            "creator":{
              "id":244,
              "name":"potatono",
              "url":"https://api.thingiverse.com/users/potatono",
              "thumbnail":"https://thingiverse-production.s3.amazonaws.com/renders/ff/46/e6/04/1f/ApocolypseBurningMan2010_thumb_medium.jpg"
            },
            "added":"2012-12-28T21:33:52-05:00",
            "modified":"2012-28-15T21:33:52-05:00",
            "is_published":true,
            "is_wip":true,
            "ratings_enabled":true,
            "like_count":1,
            "description":"This is a test thing",
            "instructions":"Print and enjoy",
            "license":"Attribution - Creative Commons",
            "files":"https://api.thingiverse.com/things/38514/files",
            "images":"https://api.thingiverse.com/things/38514/images",
            "likes":"https://api.thingiverse.com/things/38514/likes",
            "ancestors":"https://api.thingiverse.com/things/38514/ancestors",
            "derivatives":"https://api.thingiverse.com/things/38514/derivatives",
            "tags":"https://api.thingiverse.com/things/38514/tags",
            "categories":"https://api.thingiverse.com/things/38514/categories"
          }
        

Step 2. Tell Thingiverse you want to attach a file.

Use the files endpoint to tell us you want to attach a file.

Request

          POST /things/38514/files HTTP/1.1
          Content-Length: 33
          Host: api.thingiverse.com
          Authorization: Bearer e72e16c7e42f292c6912e7710c838347ae178b4a
          Content-Type: application/json; charset=utf-8

          {"filename":"SuperCoolThing.stl"}
        

Response

          HTTP/1.1 200 OK
          Date: Fri, 28 Dec 2012 01:51:20 GMT
          X-RateLimit-Remaining: 299
          Content-Length: 951
          Content-Type: application/json; charset=utf-8

          {
            "action":"https://thingiverse-staging.s3.amazonaws.com/",
            "fields":{
              "AWSAccessKeyId":"0S2CMSXYJEXCGHRR6K82",
              "bucket":"thingiverse-production",
              "key":"uploads/84/37/86/ef/74/SuperCoolThing.stl",
              "acl":"public-read",
              "success_action_redirect":"https://api.thingiverse.com/files/111382/finalize",
              "policy":"eyJleHBpcmF0aW9uIjoiMjAxMi0xMi0yOVQwMTo1MToyMVoiLCJjb25kaXRpb25zIjpbeyJhY2wiOiJwdWJsaWMtcmVhZCJ9LHsiYnVja2V0IjoidGhpbmdpdmVyc2Utc3RhZ2luZyJ9LFsiZXEiLCIka2V5IiwidXBsb2Fkc1wvODRcLzM3XC84NlwvZWZcLzc0XC90ZXN0LnN0bCJdLFsiZXEiLCIkQ29udGVudC1UeXBlIiwiYXBwbGljYXRpb25cL3NsYSJdLFsiZXEiLCIkQ29udGVudC1EaXNwb3NpdGlvbiIsIiJdLFsiY29udGVudC1sZW5ndGgtcmFuZ2UiLDEsMjYyMTQ0MDAwXSx7InN1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0IjoiaHR0cDpcL1wvYXBpLnRoaW5naXZlcnNlLmRldjo4ODg4XC9maWxlc1wvODdcL2ZpbmFsaXplIn1dfQ==",
              "signature":"broAvG9HGPcMgGdxNFuXLUd7cSU=",
              "Content-Type":"application/sla",
              "Content-Disposition":""
            }
          }

        

Step 3. Use the data from Thingiverse to upload to S3.

Use an HTTP POST to the endpoint noted in the action field and with the data contained in the other fields to send the file to S3. Note that you will need to use the HTTP encoding type multipart/form-data, which is different than the typical encoding of application/x-www-form-urlencoded. Most HTTP libraries will have some setting for this as part of their initialization but if you really need to get into the nitty-gritty see the W3C recommendation on the subject.

If you're doing an upload through a web-form or directly through javascript you may want to look at some of the new HTML5 File APIs .

Watch out! Make sure you send the parameters in the same order you received them otherwise S3 may refuse to accept them.
Also, do not set the Authorization header that you use for Thingiverse.

Request

          POST / HTTP/1.1
          Host: thingiverse-production.s3.amazonaws.com
          Content-Type: multipart/form-data; boundary=---------------------------66289253989742337765937765
          Content-Length: 12357

          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="AWSAccessKeyId"

          0S2CMSXYJEXCGHRR6K82
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="bucket"

          thingiverse-production
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="key"

          uploads/84/37/86/ef/74/SuperCoolThing.stl
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="acl"

          public-read
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="success_action_redirect"

          https://api.thingiverse.com/files/111382/finalize
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="policy"

          eyJleHBpcmF0aW9uIjoiMjAxMi0xMi0yOVQxOTozNDoyN1oiLCJjb25kaXRpb25zIjpbeyJhY2wiOiJwdWJsaWMtcmVhZCJ9LHsiYnVja2V0IjoidGhpbmdpdmVyc2UtcHJvZHVjdGlvbiJ9LFsic3RhcnRzLXdpdGgiLCIka2V5IiwidXBsb2Fkc1wvIl0sWyJzdGFydHMtd2l0aCIsIiRDb250ZW50LVR5cGUiLCIiXSxbInN0YXJ0cy13aXRoIiwiJENvbnRlbnQtRGlzcG9zaXRpb24iLCIiXSx7InN1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0IjoiaHR0cDpcL1wvd3d3LnRoaW5naXZlcnNlLmNvbVwvdGhpbmdzXC9maW5hbGl6ZSJ9LFsiY29udGVudC1sZW5ndGgtcmFuZ2UiLDEsMjYyMTQ0MDAwXV19
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="signature"

          dyqah6pLNWvjI4AemGsvq/vjVtE=
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="Content-Type"

          application/sla
          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="Content-Disposition"


          -----------------------------66289253989742337765937765
          Content-Disposition: form-data; name="file"; filename="SuperCoolThing.stl"
          Content-Type: application/sla
          ... A BUNCH OF BINARY DATA ...
          -----------------------------66289253989742337765937765
        

Response

          HTTP/1.1 303 See Other
          x-amz-id-2: QoSYmZuCUprlAs2MPJ/zQ9j+e9w9rwOqWvWaOULZE128hNcD9X/0mxBSjUPDykRw
          x-amz-request-id: 0AED157086A14FE5
          Date: Fri, 28 Dec 2012 19:34:22 GMT
          ETag: "6e9a200750aafebcfecfc2f895913455"
          Location: https://api.thingiverse.com/files/111382/finalize/?bucket=thingiverse-production&key=uploads%2FSuperCoolThing.stl&etag=%226e9a200750aafebcfecfc2f895913455%22
          Content-Length: 0
          Server: AmazonS3
        

Step 4. Once the upload is complete, let Thingiverse know.

Send a HTTP POST to the URL given in the "success_action_redirect" parameter you received in Step 2 to let Thingiverse know to check on the file. This step isn't strictly necessary as we'll check on it automatically after awhile, but it will speed up the process of getting your file up and working.

Watch out! Make sure you have the Authorization header set for this request

Request

          POST /files/111382/finalize HTTP/1.1
          Host: api.thingiverse.com
          Content-Type: application/json; charset=utf-8
          Content-Length: 0
          Authorization: Bearer e72e16c7e42f292c6912e7710c838347ae178b4a
        

Response

          HTTP/1.1 200 OK
          Date: Fri, 28 Dec 2012 01:53:35 GMT
          X-RateLimit-Remaining: 299
          Content-Length: 951
          Content-Type: application/json; charset=utf-8

          {
            "id": 111959,
            "name": "SuperCoolThing.stl",
            "url": "https://www.thingiverse.com/download:111959"
          }
        

That's it!

Once you've finalized your upload it will just take Thingiverse a few moments to process it before it goes live. If you're uploading an image or a file that we're able to render into an image, you may want to check back periodically to see if we've completed all the processing.