Skip to main content
POST
Twitter media upload API for tweets, replies & DMs
10 credits per call · All plans from $0.00012/credit
Call POST /x/media. This Twitter API media upload route accepts one local file or hosted HTTPS media URL. A Twitter API upload media request uses one connected X account. A completed upload returns a media ID and reusable mediaUrl. Skip this endpoint when a tweet already has public HTTPS media URLs. Call Create Tweet directly with those URLs.

Use the Twitter API upload media workflow

Send multipart/form-data for a file. Send application/json for a hosted URL. Authenticate with an API key or OAuth bearer token. Add one Idempotency-Key per intended upload. Any HTTP client works.

Upload a hosted media URL

Both inputs return the same lifecycle record. Poll statusUrl after 202. Store mediaId, mediaUrl, the account, and the idempotency key.

Handle media types, large videos & multiple images

Supported media files include AVIF, GIF, JPEG, PNG, WebP, and MP4. Every media type requires validation before upload. Match the content type to the file. Use a public URL. Private and reserved addresses are rejected. The download timeout is 30 seconds. The file limit is 15,728,640 bytes. Set is_long_video to true for MP4 files longer than 140 seconds. Xquik handles the chunked upload and media category internally. Send one request, then poll its lifecycle. For multiple images, call once per file. Collect up to 4 mediaUrl values. Send them together in Create Tweet. DMs accept exactly one media ID. Schedulers store mediaUrl until send time. This endpoint does not schedule tweets.

Store the Twitter API media upload receipt

Store the account, success, source reference, and idempotency key with each receipt. For replies, add reply_to_tweet_id in Create Tweet. Never send media_ids to Create Tweet. Use public mediaUrl values. Tweet and reply writes cost 30 credits, plus media surcharges. DM writes cost 10 credits.

Fix Twitter media upload API errors

Fix invalid fields or content types after 400. Replace credentials after 401. Add credits after 402. Reconnect the X account after 403. Connect a missing account after 404. Keep the original action after 409. Replace unreachable or private URLs after 422 media_download_failed. Replace rejected media after other 422 errors. Honor Retry-After after 429. Check safeToRetry after 500 or 503.

Headers

string
required
Your API key. OAuth bearer authentication is also supported. Generate a key from the dashboard.
string
required
Unique key for this intended write. Reuse it only for an exact network replay.
string
required
Use multipart/form-data when uploading a file. Use application/json when providing a URL.

Body

string
required
A connected X username or account ID. The account performs the upload.
binary
Required without url. Accepts AVIF, GIF, JPEG, PNG, WebP, or MP4.
string
Required without file. Provide a public HTTPS URL. AI agents and MCP clients can send URLs instead of binary uploads.
boolean
Multipart MP4 uploads only. Set true when the video exceeds 140 seconds. Defaults to false.

Response

Connect the requested account, then submit a newly approved write.

Durable write recovery

Send one unique Idempotency-Key per intended write. Reuse it only for the same account, target, payload, and media.
  1. Store id, the nested hash in request, billing, and statusUrl.
  2. Poll after Retry-After or pollAfterMs when terminal is false.
  3. Trust safeToRetry and nextAction before any new write.

200 Terminal or 202 active

Store terminal results. Poll active actions without creating another write.
  • After HTTP 200, store the result and settled billing.
  • After HTTP 202, poll the same action. Never submit another write.
  • After HTTP 400, fix the named field. Use a new idempotency key.
  • After HTTP 401, fix authentication. Do not retry unchanged.
  • After HTTP 402, fund the account before another write.
  • After HTTP 403, reconnect the account.
  • After HTTP 409, keep the original action. Use a new key for new input.
  • After HTTP 422, fix the rejected request before retrying.
  • After HTTP 429, wait for Retry-After. Preserve the same key.
  • After HTTP 500, retry only when safeToRetry is true.
  • After HTTP 503, poll while terminal is false.
See Get Write Action Status for every lifecycle field, terminal state, billing field, and retry rule.