multipart/form-data and HTTPS media URLs with application/json.
If you already have public image URLs or a public MP4 video URL for a tweet or reply, skip POST /x/media and pass those URLs directly in the media array on POST /x/tweets. Send up to 4 images or exactly 1 MP4 video up to 100 MB. Use POST /x/media when you need Xquik to host a local file, validate a generated media URL, or produce a mediaId for a DM attachment.
Need to post an MP4 tweet? If the MP4 is already a public HTTPS URL, skip upload and call Create Tweet with
media: ["https://example.com/video.mp4"]. Use POST /x/media first only when Xquik must host a local file or validate a generated URL, then pass the returned mediaUrl to POST /x/tweets.When to use this workflow
Upload a local file
Upload a local image, GIF, or MP4 with
POST /x/media and multipart/form-data.Upload generated media
Upload AI-generated media from a URL with
POST /x/media and application/json.Post tweets with public media URLs
Pass the URLs directly in the
media array on POST /x/tweets.Post tweets with media uploaded through Xquik
Pass returned
mediaUrl in the media array on POST /x/tweets.Post tweet replies with uploaded media
Pass
mediaUrl plus reply_to_tweet_id on POST /x/tweets.Send a DM with uploaded media
Pass returned
mediaId as the only item in media_ids on POST /x/dm/{userId}.Data you get
DM attachment ID
mediaId is the uploaded media ID for one-item DM media_ids arrays. Media IDs are valid for 24 hours after upload.Tweet media URL
mediaUrl is the public media URL for tweet media arrays.Upload confirmation
success is true after upload completes.Tweet confirmation
tweetId is returned by POST /x/tweets after the media tweet or reply is confirmed.End-to-end media handoff
Use one checkpoint object after upload and the downstream tweet, reply, or DM write. Keep the field boundary explicit: tweets and replies use publicmediaUrl values in media; DMs use the uploaded mediaId as the only
media_ids item.
Upload checkpoint
Store returned
mediaId, mediaUrl, success, source URL or filename, and the upload endpoint.Tweet URL checkpoint
Store the public
mediaUrl in media, plus returned tweetId, chargedCredits, and optional writeActionId.Reply URL checkpoint
Store
reply_to_tweet_id, public mediaUrl, returned tweetId, and pending confirmation state when present.DM ID checkpoint
Store exactly one uploaded
mediaId in media_ids, plus returned messageId and recipient ID.Field boundary
Reject tweet handoffs that put uploaded media IDs in
media or send media_ids to POST /x/tweets.Audit row
Store upload, tweet, reply, and DM IDs together so downstream systems can reconcile each media path.
Step 1: Upload media by URL
Use JSON URL upload when an AI agent, MCP client, or workflow tool has a generated image or MP4 URL that Xquik should validate and host. For tweet-only workflows with already public image URLs or exactly 1 public MP4 video URL up to 100 MB, callPOST /x/tweets directly with media.
The URL must use HTTPS, resolve to a public address, return a supported media content type, finish within 30 seconds, and stay under the 15,728,640-byte URL download cap.
URL upload checklist
HTTPS URL
Non-HTTPS URLs return
422 media_download_failed.Public host
Private or reserved IP targets are rejected.
Supported content type
AVIF, GIF, JPEG, PNG, WebP, and MP4 are accepted.
Size cap
Larger URL downloads than 15,728,640 bytes return
422 media_download_failed.30-second response window
Slow origins can time out before upload starts.
Step 2: Post a tweet or reply with mediaUrl
POST /x/tweets accepts public media URLs in media. Send up to 4 images or exactly 1 MP4 video up to 100 MB. Use the mediaUrl returned by POST /x/media. Text-only tweet or reply writes cost 30 credits; attached media adds 2 credits per started MB across all files.
media URL array and add reply_to_tweet_id.
tweetId, chargedCredits, original mediaUrl, and parent reply_to_tweet_id so queues, CRMs, support tickets, or agents can reconcile the posted reply. If the response is 202 with x_write_unconfirmed, store writeActionId, chargedCredits, and poll Get write action status instead of sending the same tweet again.
Do not send media_ids to POST /x/tweets. That endpoint rejects media_ids and expects the media URL array instead.
Step 3: Send a DM with mediaId
POST /x/dm/{userId} accepts one uploaded media ID in media_ids. Use the mediaId returned by POST /x/media.
media_ids field for text-only DMs.
Store message_id, media_id, recipient, account, and send status in shared handoff rows. Keep full DM body text in private systems only.
JSON Lines handoff
For queues, CRM syncs, warehouse loads, or agent memory, write one record per upload and downstream write toxquik-media-handoff.jsonl.
Media upload row
Tweet or reply row
DM media row
media_url for tweet and reply media arrays. Use media_id for the single DM media_ids item.
Step 4: Upload a local file
Use multipart upload when your app has the file bytes. Supported formats are AVIF, GIF, JPEG, PNG, WebP, and MP4.is_long_video=true.
Cost and error handling
Upload media costs 10 credits per upload call. Posting a tweet or reply is a separate 30-credit create-tweet call before media surcharges; sending the DM is a separate 10-credit write call.Invalid input
Status
400. Error invalid_input. Check account, file type, file presence, URL presence, and is_long_video.Billing or credits
Status
402. Errors no_subscription or insufficient_credits. Subscribe or top up credits before retrying.Reconnect account
Status
403. Error account_needs_reauth. Reconnect the X account from the dashboard.Media download failed
Status
422. Error media_download_failed. Use an HTTPS URL that returns a supported media file, or switch to multipart upload.Rate limit or temporary failure
Status
429 or 503. Retry with exponential backoff and respect Retry-After when present.Handoff checklist
Tweet workflow
Save
mediaUrl and pass it to POST /x/tweets as media.Reply workflow
Save the parent tweet ID,
mediaUrl, returned tweetId, and any writeActionId.DM workflow
Save
mediaId and pass it to POST /x/dm/{userId} as one media_ids item.JSON Lines
Store upload, tweet/reply, or DM handoff rows in
xquik-media-handoff.jsonl with media_id and media_url.Agent workflow
Use JSON URL upload only when the agent needs Xquik to validate or host a
generated URL, or needs a DM
mediaId. For tweet-only public URLs, pass
them directly to POST /x/tweets.File workflow
Prefer multipart upload when your app owns the file bytes.
Related: Upload Media · Create Tweet · Send Direct Message