Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.x.com/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through uploading videos and large media files using the chunked upload workflow. For video or large media uploads, you must:
  1. INIT — Initialize the upload and get a media_id
  2. APPEND — Upload each chunk of the file
  3. FINALIZE — Complete the upload
  4. STATUS — (If needed) Wait for processing to complete
See this sample code for a complete Python example.

Step 1: Initialize upload (INIT)

Start the upload session to get a media_id:
cURL
curl -X POST "https://api.x.com/2/media/upload" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: multipart/form-data" \
  -F "command=INIT" \
  -F "media_type=video/mp4" \
  -F "total_bytes=1048576" \
  -F "media_category=amplify_video"
Response:
{
  "data": {
    "id": "1880028106020515840",
    "media_key": "13_1880028106020515840",
    "expires_after_secs": 1295999
  }
}

Step 2: Upload chunks (APPEND)

Upload each chunk of the file. For example, split a 3 MB file into 3 chunks:
cURL
curl -X POST "https://api.x.com/2/media/upload" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: multipart/form-data" \
  -F "command=APPEND" \
  -F "media_id=1880028106020515840" \
  -F "segment_index=0" \
  -F "media=@/path/to/chunk1.mp4"
Chunking advantages:
  • Improved reliability on slow networks
  • Uploads can be paused and resumed
  • Failed chunks can be retried individually

Step 3: Finalize upload (FINALIZE)

Complete the upload after all chunks are sent:
cURL
curl -X POST "https://api.x.com/2/media/upload" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: multipart/form-data" \
  -F "command=FINALIZE" \
  -F "media_id=1880028106020515840"
Response:
{
  "data": {
    "id": "1880028106020515840",
    "media_key": "13_1880028106020515840",
    "size": 1048576,
    "expires_after_secs": 86400,
    "processing_info": {
      "state": "pending",
      "check_after_secs": 1
    }
  }
}
If processing_info is returned, proceed to Step 4 to wait for processing. If not, the media is ready to use.

Step 4: Check status (STATUS)

If processing_info was returned, poll for processing completion:
cURL
curl "https://api.x.com/2/media/upload?command=STATUS&media_id=1880028106020515840" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN"
Processing states: pendingin_progresssucceeded or failed

Step 5: Create Post with media

Once processing is complete, create a Post with the media:
cURL
curl -X POST "https://api.x.com/2/tweets" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Check out this video!",
    "media": {
      "media_ids": ["1880028106020515840"]
    }
  }'

Media categories

CategoryDescription
tweet_imageImage for a Post
tweet_gifAnimated GIF for a Post
tweet_videoVideo for a Post
amplify_videoAmplify video

Next steps

Best practices

File constraints and requirements

Create Posts

Post with media

API Reference

Full endpoint documentation