Use media when your image or MP4 video is already a public HTTPS URL or when Upload Media returned mediaUrl. Send up to 4 image URLs or exactly 1 MP4 video URL up to 100 MB. Do not send media_ids; that field is for DMs only. Attached media adds 2 credits per started MB across all files.
Store tweetId, charged, and chargedCredits on a 200 Success response. If the API returns 202 x_write_unconfirmed, store writeActionId, poll Get Write Action Status, and do not retry-send the same body. Keep reply_to_tweet_id and media in your downstream record.
Array of public media URLs to attach directly. Send up to 4 JPEG, PNG, GIF, WebP, or AVIF image URLs, or exactly 1 MP4 video URL up to 100 MB. Do not mix video with other media. Use Upload Media first if you need Xquik to host a local file, then pass the returned mediaUrl in media. Do not pass uploaded mediaId values or media_ids. Attached media adds 2 credits per started MB across all files.
{ "error": "x_write_unconfirmed", "status": "pending_confirmation", "writeActionId": "42", "charged": false, "chargedCredits": "0", "retryable": false, "message": "Action may have completed, but confirmation is still pending."}
The write was dispatched but final confirmation is still pending. writeActionId identifies the action to poll with Get write action status. charged is false and chargedCredits is "0" while confirmation is pending, and retryable is false; do not retry-send the same tweet blindly.
{ "error": "invalid_input", "message": "Either text or media is required" }
Missing text and media, invalid account format, or other validation failure.
{ "error": "unsupported_field", "message": "media_ids is not supported on POST /x/tweets. Pass media as an array of public image or MP4 video URLs.", "retryable": false, "charged": false, "chargedCredits": "0", "details": { "action": "create_tweet", "suggestion": "Use the media field with public URLs instead of media_ids. Send up to 4 images or exactly 1 MP4 video up to 100 MB." }}
The request body contains a field the endpoint does not accept (for example media_ids).
{ "error": "unauthenticated", "message": "Missing or invalid API key" }
Missing or invalid API key.
{ "error": "no_subscription", "message": "No active subscription" }
An active subscription is required. Subscribe from the dashboard.
X rejected the write. Possible codes: x_content_too_long, x_duplicate_action, x_account_suspended, x_account_protected, x_target_not_found, x_account_feature_required, x_rejected. See error handling for details.
The request hit an Xquik tier limit, or X throttled the write. Possible codes: rate_limit_exceeded, x_rate_limited, or x_daily_limit. Respect the Retry-After header when present.
Copy tweetId from the response into tweet_id. Keep reply_to_tweet_id when the post is a reply, and store chargedCredits as charged_credits. Store the public media URLs you sent in media. If you uploaded first, store the returned mediaUrl, not the upload mediaId.
Store writeActionId as write_action_id, poll Get Write Action Status, and do not retry-send the same body while status is pending_confirmation. If polling later returns status: "success" with tweetId, update the same record to posted.