Guides · Updated

X API posting errors, explained

When POST /2/tweets fails, X answers with an HTTP status and a JSON body whose detail names the problem. The status tells you the kind of failure; the detail tells you which one. Many posting failures are a 403, and the fix depends on its detail.

Every X fact here comes from X's own documentation, checked on October 26, 2026: its response codes, rate limits, create post reference, manage posts guide, OAuth 2.0 reference, pricing, the media introduction, best practices and chunked upload pages, and X's changelog. Where X's docs don't cover an error, this guide says so.

The short answer

X answers What it means What fixes it
401 Unauthorized The token is missing, wrong, expired or revoked Refresh the token, or have the person sign in again
403, "duplicate content" The account already posted this text Change the text; sending it again won't work
403, "not permitted to perform this action" X won't take this post from this app for this account Check the app's access and the token's scopes, then the reply and quote rules
A refused reply The post's author didn't mention or quote your account Reply by hand in X, or make it a post of its own
A refused quote Quote posts need X's Enterprise plan Quote it by hand in X, or post it without the quote
403, "video longer than N minutes" The video is over the posting account's limit Trim it to 20 minutes, or 125 with X Premium
429 Too Many Requests A rate limit or usage cap Wait until x-rate-limit-reset, then retry
Media state failed X couldn't process the file Re-encode it to X's requirements and upload it again
500, 502, 503 or 504 A problem on X's side Check the post didn't go out, then retry with backoff

401: the token

X's response codes page puts a 401 down to invalid or missing credentials. Check, in order:

403: read the detail

A 403 means X knows who you are but refused the action. The response codes page lists the usual reasons: the app doesn't have access to the endpoint, the endpoint needs enrollment or approval (problem type client-forbidden, "App not enrolled or lacks required access"), the token lacks a scope, or the resource is private or protected. For a post, the detail tells you which case you're in.

"You are not allowed to create a Tweet with duplicate content."

X refuses a post whose text repeats one the account already posted. X's error reference doesn't list this detail, and X doesn't publish how far back it looks.

"You are not permitted to perform this action."

This is X's general refusal for a post, and X's error reference doesn't explain it either. Work through the causes X does document:

  1. The app's setup. X's manage posts guide requires a developer App inside a Project in the Developer Console.
  2. Scopes. The token must carry tweet.write. Scopes are granted at sign-in, so after you add one, have the person sign in again for a token that has it.
  3. A reply or a quote. Self-serve access refuses most of them; see below.
  4. More than one cashtag. On self-serve access, a post may carry one cashtag (such as $TICKER); X rejects more.
  5. Credits or the spending limit. See below.

Replies to other accounts

Since February 23, 2026, self-serve (pay-per-use) apps can reply only when the original post's author has summoned the replying account: mentioned it in that post, or quoted one of its posts. X rejects any other reply. X says the change targets automated, low-quality replies, and that Enterprise access isn't affected. Its docs don't give the error body.

Quote posts

X's create post reference now opens with a warning: quote-posting with quote_tweet_id requires an Enterprise plan and isn't available on self-serve (pay-per-use) tiers. X's changelog entry of April 16, 2026 lists quote posts, with following and likes, as removed from all self-serve tiers. Its docs don't give the error body.

"This user is not allowed to post a video longer than N minutes."

The video uploaded, but it's longer than the posting account may post. X checks again when you attach a media_id, against the posting account's status rather than your API plan: 20 minutes and 8 GB by default, 125 minutes and 16 GB for X Premium or verified accounts. Trim the video, or post it from an account with the longer limit.

Credits and the spending limit

On pay-per-use, X blocks requests once the credit balance runs out (it can dip slightly below zero first), or once the billing cycle's spending limit is reached, until you add credits or the next cycle starts. X's pricing page says so but doesn't publish the response. Flaghand recognizes two answers seen in practice: a 402 with CreditsDepleted, and a 403 whose detail says the account "has reached its billing cycle spend cap" (how Flaghand handles them). Add credits, or raise the spending limit in the Developer Console. What each call costs.

429: too many requests

X's response codes page gives 429 for "Rate limit or usage cap exceeded", with problem types rate-limit-exceeded and usage-capped. Every response carries x-rate-limit-limit, x-rate-limit-remaining and x-rate-limit-reset (a Unix time). Wait until the reset, then retry; X recommends exponential backoff for 429s.

The posting limits in X's rate limits table:

Endpoint Per user Per app
POST /2/tweets: each post, reply and thread part 100 per 15 minutes 10,000 per 24 hours
POST /2/media/upload/initialize, /append and /finalize 1,875 per 15 minutes 180,000 per 24 hours
GET /2/media/upload: processing status 1,000 per 15 minutes 100,000 per 24 hours
POST /2/media/metadata: alt text 500 per 15 minutes 50,000 per 24 hours

Media: upload, processing and size

Media goes up before the post: initialize, append the file in segments, finalize, then check its status if finalize returns processing_info. Each step can fail on its own:

X's limits, checked at upload and again when the post is created:

Media X's limit
Photo: JPG, PNG, GIF or WEBP 5 MB
Animated GIF 15 MB. X recommends at most 1280x1080, 350 frames and 300 million pixels in all
Video, most accounts 0.5 seconds to 20 minutes, up to 8 GB
Video, X Premium or verified Up to 125 minutes and 16 GB
Alt text 1,000 characters
Per post Up to 4 photos, 1 animated GIF or 1 video

An upload that succeeded doesn't guarantee the post: POST /2/tweets checks the limits again, which is where the video-length 403 comes from.

500, 502, 503 and 504

These are X's side: wait and retry with backoff, and check X's API status. Before you retry a post, read the account's latest posts. If the first attempt went out, the retry can come back as duplicate content.

Posting through Flaghand

Flaghand's check catches several of these before anyone approves a post: text over the account's limit (280 weighted characters, or 25,000 when X reports a Basic, Premium or PremiumPlus subscription), more than 4 media, a video mixed with photos, a photo over 5 MB or a GIF over 15 MB, alt text over 1,000 characters, and any quote post, even of your own post. For a quote it offers to post it yourself in X or drop the quote; for a thread, you can post the opening quote yourself and let Flaghand post the rest under it (draft rules).

When X refuses an approved post anyway:

Flaghand's own API answers with its own error codes.

Get access to Flaghand.