Errors & blockers

Chunked media upload for a social API

When and why a social publishing API needs chunked media upload instead of a single request, and how it works.

Quick answer

Chunked upload splits a large media file into independently uploaded parts, so a failure only costs the piece that failed instead of restarting a multi-hundred-megabyte transfer. Nearly every protocol shares three phases: initiate a session with filename, MIME type, and byte count; upload parts independently; then finalize with per-part checksums or ETags so the server can verify nothing was dropped.

A video file measured in hundreds of megabytes doesn't behave like a JSON body. Send it as one request and you're betting the entire upload on a single uninterrupted connection, a request timeout long enough to cover it, and a server willing to buffer the whole thing in memory. Chunked upload exists to remove that bet — split the transfer into independent pieces, and a failure only costs you the piece that failed.

PostGate handles OAuth, publishing and delivery evidence for every network through one API. Start free or read the docs.

01

Why does a single request body break down for large media?

Most infrastructure between a client and an API — load balancers, reverse proxies, the framework's own body parser — has a practical ceiling on request size, often well under the size of an uncompressed video. Even under that ceiling, a multi-hundred-megabyte upload over a mobile or unreliable connection takes long enough that something drops the connection before it finishes, and a single-request upload has no concept of partial progress: one dropped byte and you restart from zero. Buffering the whole file server-side before doing anything with it also means memory usage scales with the largest file anyone uploads, which is a bad property for a shared service.

02

What shape do most chunked upload protocols share?

Strip away the vendor-specific naming and almost every chunked upload protocol has the same three phases. Initiate: tell the server the filename, MIME type, and total byte count up front, and get back either a session identifier or a set of upload targets. Upload parts independently: send each chunk as its own request, in any order the protocol allows, so a single failed part can be retried without touching the parts that already succeeded — and parts can sometimes upload in parallel. Finalize: tell the server every part has arrived, usually supplying a checksum or an identifier per part (an ETag, most commonly) so it can verify nothing was dropped or reordered before assembling the final file.

03

Does PostGate's media API do this? Yes — via multipart upload

POST /api/media supports exactly this flow for large files. Create a reservation with the filename, MIME type, and byte count; PostGate returns signed URLs to upload each part to directly. Upload every part, collect the ETag each one returns, then send those ETags to the completion endpoint. If you no longer need a pending reservation — the user canceled, or something upstream failed — abort it explicitly instead of leaving it dangling. See the Media resource reference for the complete flow.

Start and complete a multipart uploadPostGate API
# 1. Reserve the upload
curl -X POST https://postgate.studio/api/media \
  -H "Authorization: Bearer $POSTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "upload",
    "filename": "campaign.mp4",
    "mime": "video/mp4",
    "bytes": 52428800
  }'
# -> { "id": "med_01JXYZ", "upload": { "parts": [{ "url": "https://...", "part": 1 }, ...] } }

# 2. PUT each part to its signed URL, collecting the response ETag per part

# 3. Complete the upload with the collected ETags
curl -X POST https://postgate.studio/api/media/med_01JXYZ/complete \
  -H "Authorization: Bearer $POSTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "parts": [{ "part": 1, "etag": "\"9f86d0...\"" }] }'

# Abort instead, if you no longer need the reservation
curl -X DELETE https://postgate.studio/api/media/med_01JXYZ/upload \
  -H "Authorization: Bearer $POSTGATE_API_KEY"
04

When should you use it instead of a URL or base64?

Multipart upload isn't the default path — it's the right tool for a specific case. If the asset already lives at a public URL, pass that URL directly to POST /api/media or straight into a post's media array; PostGate fetches it asynchronously, detects the true MIME type, and probes its dimensions and duration on its own. Use a pre-uploaded media ID — via multipart for large files, or a plain upload for small ones — when the asset is large, will be reused across several posts, or needs to be validated before a post is scheduled rather than discovered invalid at publish time.

05

Is this the same as the destination platform's own chunking?

Your upload to PostGate is one chunked relationship. Delivering that same file to a platform like X is a completely separate one — X's own media/upload endpoint requires its own INIT/APPEND/FINALIZE sequence for video, GIFs, and any image over roughly 5 MB, entirely independent of how the file reached PostGate in the first place. You never have to implement that second protocol: PostGate runs it internally once your post targets that platform. See X's chunked upload protocol for what that looks like on the wire.

Frequently asked questions

Why can't I upload a large video in a single request?

Most infrastructure between a client and an API — load balancers, reverse proxies, the framework’s own body parser — has a practical request-size ceiling, often well under an uncompressed video. Even below that ceiling, a long upload over an unreliable connection tends to drop before it finishes, and a single-request upload has no concept of partial progress: one dropped byte and you restart from zero. Buffering the whole file server-side also makes memory usage scale with the largest file anyone uploads.

How does PostGate's multipart media upload work?

Create a reservation with POST /api/media, passing the filename, MIME type, and byte count; PostGate returns signed URLs to upload each part to directly. Upload every part, collect the ETag each one returns, then send those ETags to the completion endpoint. If you no longer need a pending reservation — the user canceled, or something upstream failed — abort it explicitly instead of leaving it dangling.

When should I use multipart upload instead of passing a URL?

If the asset already lives at a public URL, pass that URL directly to POST /api/media or straight into a post's media array — PostGate fetches it asynchronously, detects the true MIME type, and probes dimensions and duration on its own. Use a pre-uploaded media ID (multipart for large files, plain upload for small ones) when the asset is large, will be reused across several posts, or needs validating before a post is scheduled.

Do I also have to implement each platform's own chunked upload protocol?

No. Your upload to PostGate and delivery to the destination platform are separate relationships. X's media/upload endpoint, for example, requires its own INIT/APPEND/FINALIZE sequence for video, GIFs, and images over roughly 5 MB — but PostGate runs that protocol internally once your post targets the platform, so you never implement it yourself.

Build it with PostGate

One API for every social platform your customers care about — sandboxed, documented, and ready today.

Start building Read the docs