X API video upload: chunked only, 0.5 s minimum, 20-minute cap
X's media docs require chunked upload for all videos, set a 0.5-second minimum and a 20-minute cap for non-Premium posts. Trim a clip for DMs with video_trim.

X's media documentation says to use chunked upload for all videos; the simple POST to /2/media/upload is for images and small files only. It lists a 0.5-second minimum duration, and for non-Premium accounts 20 minutes and 8 GB for post videos, with DM videos at 140 seconds and 512 MB. Check the file before you start the upload, because the limits are per category.
What are the limits? (read 2026-10-09)
The page has no fields about AI or synthetic labels, so this post makes no claim about them.
| Category | Non-Premium | Premium |
|---|---|---|
| Post video (tweet_video, amplify_video) | 20 minutes, 8 GB | 125 minutes, 16 GB |
| DM video (dm_video) | 140 seconds, 512 MB | 10 minutes, 1 GB |
| Minimum duration | 0.5 seconds | 0.5 seconds |
| Upload method | Chunked for all videos | Chunked for all videos |
How do you check a file first?
Probe it with video_inspect. The result gives duration_seconds and size_bytes, enough to compare against the table: under 0.5 s fails, over 20 minutes fails for a default account, and over 140 s or 512 MB fails as a DM video. The source can be up to 1800 seconds, which covers the 20-minute post cap.
How do you cut to fit?
- For a DM, cut to 140 seconds or less with video_trim: set start and duration, precision exact, $0.02 per job.
- For a post over 20 minutes on a default account, split into parts; each trim job accepts 0.2 to 900 seconds of output.
- If the size is over the cap, shorten it or use the output option (width and height 256 to 2160; fps 24, 25, 30 or 60) to shrink the frame.
- Poll /v1/jobs/:id/status and /result for the async trim, since there is no GET route for it.
Where does Sume stop?
Sume prepares the file; it does not post to X. Your code does the chunked upload against the X API with the credentials you hold. Keep the trimmed file's URL and the probe next to the post record so you can show what was sent.
Keep the account type in your config. The limits differ for Premium and non-Premium accounts, and the same file can pass for one and fail for the other. Read the category from the endpoint you call rather than guessing, and re-read the X page before a launch, since limits can change.
Sources
Related posts
More in Developers
- Wan 3.0 X-DashScope-Async header and polling vs Sume
Alibaba needs an X-DashScope-Async: enable header and suggests polling about every 15 seconds. Sume is async by default and hands you a polling_url.
- Empty job_id next to job_ids: how Sume MCP treats placeholders
Some agent clients fill every optional tool field with empty strings, zeros and empty arrays. What Sume's MCP drops, what it keeps, and what still errors.
- On a 402, try a cheaper rung: a Python ladder with fresh keys
A 402 on Sume means nothing was reserved, so a cheaper request can go straight through. Python ladder: Seedance 720p, 480p, then Wan 480p, one key per rung.
- Sume failed job says [redacted_url]: what was removed
A [redacted_url] in a Sume job error is by design: URLs, provider ids, env names and secrets are masked, and the provider reason is capped at 300 characters.
Written by Sume