X API 403: Not Allowed to Post a Video Longer Than N Minutes

Sep 18, 2026

A 403 whose detail reads "This user is not allowed to post a video longer than 20 minutes." does not mean your upload failed — it means the upload succeeded and the Post creation was refused. Those are two different checks in X's API, and X says so explicitly.

That is why the failure feels wrong: every byte went up, finalize succeeded, processing reported success, and the error only appears on the very last call.

What this error actually means

X's media best-practices page states the rule in one sentence: "Upload limits and Post-create limits are separately enforced. A media_id that finalized successfully can still be rejected by POST /2/tweets."

Read that as two gates, not one. The upload gate checks whether the bytes can be ingested. The Post-create gate checks whether this account is allowed to publish media of that length. Clearing the first tells you nothing about the second.

The chunked media upload page gives the complete response body:

{
  "title": "Forbidden",
  "detail": "This user is not allowed to post a video longer than 20 minutes.",
  "type": "about:blank",
  "status": 403
}

The best-practices page documents the same string with the number left as a variable:

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

and explains it: "N is the posting user's cap for that media (20 minutes by default, 125 minutes for Premium / verified Post video). Handle this error even after a successful finalize."

That last clause is the design intent, in X's own words. This 403 is not an edge case to be avoided — it is an expected outcome that your integration is supposed to catch after a clean finalize.

Whose limits are being applied

Not yours as a developer. X is unusually direct about this: "Limits follow the authenticated user (X Premium / verified status), not your developer API plan."

The introduction page repeats it with the underlying flag named: "These Post-video caps match the X app. Premium status is the uploading user's X Premium / verified subscription (feature/long_video_upload), not your developer API plan."

So upgrading your API tier changes nothing here. If the authenticated account is a default account, the cap in the message is the default cap, no matter what you pay for access.

The fastest fix: confirm the category you sent

Before you touch the video, check the media_category you passed at INIT. X names this as a common cause of exactly this failure pattern: "Using the wrong category (for example a DM category on a Post) is a common reason an upload succeeds and Post create then fails."

The reason is that the category is the limit selector. From the best-practices page: "The Media Category parameter defines the use case of the media file to be uploaded, and can affect file size limits or other constraints enforced for media uploads. It's important to use the correct media category when uploading media to avoid problems when trying to use the media. It is an optional value passed in the INIT request as part of the upload flow. If media category is not specified, the uploaded media is assumed to be media for a Post (tweet_image, tweet_video, or tweet_gif), depending on the content type."

Here is the published table of categories and their caps:

CategoryUse forTypical max (default / Premium)
tweet_videoVideo on a Post20 min / 8 GB · Premium: 125 min / 16 GB
amplify_videoAds / promoted video20 min / 8 GB · Premium: 125 min / 16 GB
dm_videoVideo in a Direct Message140 s / 512 MB · Premium: 10 min / 1 GB
subtitlesSubtitle file1 MB

Note the spread: a clip that is perfectly legal as tweet_video is far past the ceiling as dm_video. X's guidance on which to pick is short — "Use tweet_video for a regular Post. Use amplify_video for Ads creatives. For Posts, Premium and default duration/size caps are the same for tweet_video and amplify_video."

Try it right here

Runs in your browser. Your file is not uploaded anywhere.

Loading tool…

Be clear about what compression does and does not solve here. This 403 names a duration, and re-encoding does not make a video shorter. What compression clears is the other column of that table: the size ceiling attached to each category. If your clip is inside the duration cap but the file is enormous, shrinking it before upload is the right move — and the compressor above runs in your browser, so the file is not uploaded anywhere on the way. More on the trade-offs in how to compress a video without losing quality, or go straight to the compressor.

Other causes, in order of likelihood

1. The category was omitted entirely. It is optional, and when it is missing the media "is assumed to be media for a Post ... depending on the content type." That default is usually what you wanted for a Post — but it means you never actually confirmed the category, so it is worth sending explicitly while debugging.

2. The account really is over its cap. If the authenticated user is a default account and the message says 20 minutes, a 25-minute cut is not going to publish. The fix is a shorter video or a different posting account, not a retry.

3. You are confusing this with the size gate, which fails elsewhere. Size problems surface earlier: "POST /2/media/upload/initialize accepts total_bytes up to 16 GB. Passing a larger total_bytes than the account is allowed to upload fails at initialize or finalize." If your failure is at POST /2/tweets, it is not that.

4. The number in the message does not match what you read in the Help Center. It often will not. For default accounts, the developer docs list Post video as "0.5 seconds–20 minutes 8 GB", while the Help Center says "If you aren't a Premium subscriber, you can still upload videos up to 140 seconds long with a maximum file size of 512MB." For Premium, the developer docs say 125 minutes while other official pages say roughly 3 hours or under 4 hours. All of those are on X's own pages. Treat the number returned in the 403 as what the API enforced for that request, and check the current limit in the official documentation before hard-coding anything.

How to tell it worked

There is no way to pre-flight this gate — it only answers on Post creation. So verify in this order:

  1. Upload path is healthy. Processing moves through the documented states: pendingin_progresssucceeded or failed. A succeeded here is necessary, not sufficient.
  2. Category is what you intended. Log the media_category you sent at INIT alongside the media_id, so a later 403 can be traced back to it.
  3. Re-issue POST /2/tweets. A 200 is the only real confirmation. Because the two gates are separate, the same media_id can be valid media and still be refused for the Post.
  4. Keep the handler. X asks you to "Handle this error even after a successful finalize", so this should be a branch in your code, not a one-time fix.

FAQ

Does this 403 mean my upload failed? No. It is raised by Post creation, after the media has been accepted. X states that upload limits and Post-create limits are separately enforced, and that a media_id that finalized successfully can still be rejected.

Will a higher API tier remove this limit? No. X writes that limits follow the authenticated user's X Premium or verified status, "not your developer API plan."

Why does the message say 20 minutes when the Help Center says 140 seconds? Both numbers appear on official X pages for default accounts — the developer docs list 20 minutes for Post video, the Help Center says 140 seconds. X has no page that reconciles them, so check the current limit in the official documentation rather than assuming one is stale.

Can I fix this by compressing the video? Only if the blocker is file size. The 403 quoted here is about duration, and compression does not change duration. See the other X limit articles for the size-side failures.

Does media_category really change which limit applies? Yes. X says the parameter "defines the use case of the media file to be uploaded, and can affect file size limits or other constraints", and names a wrong category — such as a DM category on a Post — as a common reason an upload succeeds and Post create then fails.


Quotes from X's developer documentation for media upload and its Help Center, checked 16 September 2026. X publishes different numbers for the same limit on different pages — verify against the official docs before relying on any of them. Browser-based conversion and compression tools: all Clapr tools.

Clapr team

Clapr team

X API 403: Not Allowed to Post a Video Longer Than N Minutes | Clapr Blog