Uploading Media

All media uploads require the use of the Media Upload endpoints. While images can be uploaded directly using the simple upload endpoint, videos and other media types require the use of the multi-part chunked upload endpoint which consists of three distinct steps: INIT, APPEND and FINALIZE.

Additionally, it is worth calling out the additional_owners parameter. This value can be set to a list of user IDs that are allowed to use this media. For example, in order to upload a media entity to one account and then share the entity the @furni account, the additional_owners parameter can be set to 3805104374 (which corresponds to @furni).

Simple Upload

The simple upload endpoint can only be used to upload images.

   twurl -X POST -H upload.twitter.com "/1.1/media/upload.json?media_category=TWEET_IMAGE&additional_owners=3805104374" -f adsapi-heirarchy.png -F media 


   "media_id": 931270813906374700,
   "media_id_string": "931270813906374657",
   "media_key": "3_931270813906374657",
   "size": 95294,
   "expires_after_secs": 86400,
   "image": {
     "image_type": "image/png",
     "w": 1000,
     "h": 600

where -f is the file itself while -F refers to the file field type.

The media_id_string and media_key values can then be used to attach this image to any Tweet or Card objects.

Chunked Upload

The multi-part chunked upload endpoint as the name suggests, is a multi part upload process. This endpoint was intentionally designed as such in order to allow for resumable uploads.

For example, uploading a video to the authenticated users' Twitter account, and sharing that same entity with the @furni account. First, however, we need to determine the total bytes contained in the file being uploaded:

  stat -f%z  ~/Desktop/sample-video.mp4

Files that are larger than 1MB (max chunk size) can be broken up into multiple chunks like so:

  split -b 5m  ~/Desktop/sample-video.mp4

The upload itself consists of a series of calls as illustrated below:


  twurl -X POST -H upload.twitter.com "/1.1/media/upload.json?additional_owners=3805104374" -d "command=INIT&media_type=video/mp4&media_category=amplify_video&total_bytes=5678971"

The additional_owners field is set to the user ID of the @furni account. In addition, a media_category can be used to set the type of media being uploaded, whether a Gif, Video or Amplify Video (or pre-roll video). The user ID of a user can be retrieved from the GET users/show endpoint.

Note The use of the amplify_video media category is required if uploading a video > 140 seconds in length or if being used as a creative in an Twitter Ads campaign. Whitelisting is needed at the @handle level to upload long videos. 

  "media_id": 931263015239934000,
  "media_id_string": "931263015239933952",
  "expires_after_secs": 86399,
  "media_key": "7_931263015239933952"

The media_id_string value is needed for all subsequent calls.


The APPEND command must be called as many times as necessary until all chunks (of max size 1MB) of the file have been uploaded. The segment_index value needs to be altered with each call.

  twurl -X POST -H upload.twitter.com "/1.1/media/upload.json" -d "command=APPEND&media_id=931263015239933952&segment_index=0" --file ~/Desktop/sample-video.mp4 --file-field "media"

Twurl provides some useful helpers like the -f flag to specify the media being uploaded and the --file-field flag is used to specify that the file being uploaded is a media file. Note that this endpoint does not have a response body. All other headers are still available.


The last call needed to finish the upload process is as follows:

  twurl -X POST -H upload.twitter.com "/1.1/media/upload.json" -d "command=FINALIZE&media_id=931263015239933952"
  "media_id": 931263015239934000,
  "media_id_string": "931263015239933952",
  "media_key": "7_931263015239933952",
  "size": 514065,
  "expires_after_secs": 86400,
  "processing_info": {
    "state": "pending",
    "check_after_secs": 5

The processing_info field can be used to determine whether the file is ready to be used or not. Once the state is set to "succeeded" the file is ready to be used. The media upload status endpoint can be used to check the current state of the upload.

  twurl -t -X GET -H upload.twitter.com "/1.1/media/upload.json?command=STATUS&media_id=931263015239933952" 

  "media_id": 931263015239934000,
  "media_id_string": "931263015239933952",
  "media_key": "7_931263015239933952",
  "size": 514065,
  "expires_after_secs": 83510,
  "video": {
    "video_type": "video/mp4"
  "processing_info": {
    "state": "succeeded",
    "progress_percent": 100?

Once the video is successfully uploaded, the media_id_string or media_key may be used to associate the media entity with a Tweet or Card.

The same steps can be repeated to upload a Gif, with the only change being the video_type of image/gif and the media_category of TWEET_GIF

Associating media with a Tweet

Once all steps to upload the media have been completed, the media entity can be attached to a Tweet like so

  twurl "/1.1/statuses/update.json" -d "media_ids=931263015239933952&text=Sample Tweet with media_ids and twurl"

In addition, checkout our media best practices guide for additional details around supported file formats, etc.

Ready to build your solution?

Review the documentation to get started

  • Read Previous
  • Read Next