Large files & video
The 100 MB multipart cap, source_url for big files, why video used to fail, and the direct-upload host.
Upload basics — the two request shapes and the mediaFiles schema — are on the
Posting page. This page is about big files and video: size
limits, the difference between the two upload methods at scale, and the fixes
that make large video reliable.
Pick the right method by size
Rule of thumb
Under ~100 MB: either method works. Over ~100 MB: use source_url.
| Method | Max size | Why |
|---|---|---|
source_url (JSON) | 512 MB | The request body is a tiny JSON blob; the file is fetched server-side, so the edge size limit never applies. Recommended for anything over ~100 MB, including video. |
multipart (file field) | ~100 MB | The raw bytes ride in the request body, which the edge caps at 100 MB. Larger bodies get 413 before reaching the API. |
The 413 on a large multipart upload is the edge rejecting the body, not
the application — the app itself accepts up to 512 MB. There is no
video-specific endpoint or field, and no extra headers: X-API-Key is all you
need.
Recommended: source_url
curl -X POST "$BASE/api/crm/$CRM/accounts/$OFUID/media" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"source_url":"https://<public-https-host>/clip.mp4"}'Constraints on the URL:
- Publicly reachable HTTPS. It must resolve from the public internet. A
private/VPN-only host — Tailscale
*.ts.net, a LAN address,localhost— fails atstage: "fetch"because our servers are not on your private network. - ≤ 512 MB.
- A codec the OnlyFans converter accepts (H.264 + AAC is fine). MP4 is fine.
On success you get the usual composer object; pass its media value straight
into a post/message mediaFiles array (see Posting).
Why large video used to return an empty 502 — and the fix
Historically, a large video could come back as an empty 502 with no JSON
body, while an image of the same request shape returned 200. Cause: after the
file was fetched, the upload to storage ran sequentially and through the
account proxy, and for a many-part video the total time exceeded the edge's
~100-second timeout — so the edge returned an empty 502 while the API was
still working (which is why there was no stage field).
This is fixed: the storage upload now runs in parallel and direct. A 141 MB
video completes in about 12 seconds end-to-end. Re-running a source_url
video that previously failed now returns 200.
Raw multipart over 100 MB: the direct-upload host
If a client cannot host the file at a URL and must send raw multipart bytes
above 100 MB, post to the dedicated upload host, which bypasses the edge cap:
curl -X POST "https://upload.theonlyapi.com/api/crm/$CRM/accounts/$OFUID/media" \
-H "X-API-Key: $KEY" \
-F "[email protected]"Auth and response are identical to the main endpoint; files up to ~2 GB are
accepted. Use this only for large multipart — keep all other traffic on
theonlyapi.com.
Errors
| Status | Meaning | Fix |
|---|---|---|
413 | multipart body over ~100 MB (edge cap). | Use source_url, or upload.theonlyapi.com. |
502 empty | Historic large-video timeout. | Fixed — retry; you'll get 200. |
400 stage:"fetch" | source_url not publicly reachable, or the source dropped mid-download. | Serve the file from a public URL and retry. |
403 WRITES_DISABLED | Writes are off for this account. | Enable writes first. |
Every failure carries a JSON stage (fetch / create / put / convert)
so the failing step is explicit.