Skip to content
Connect an agent

Media

Start an upload

Reserves a file and says how to send it: one PUT to uploadUrl up to 100 MB, or multipart parts for a larger video (give bytes).

POST/v1/media

TL;DR

QuestionAnswer
What does it do?Start an upload.
What does it need?An API key or an OAuth access token.
What does it take?A JSON body with the fields below.
What does it return?Status 201 with a body of type MediaUpload.
In the SDK?flung.media.create()
What can go wrong?401 Missing, unknown, revoked or expired API key; 422 The request failed validation; 429 Too many requests for this credential; wait for retry-after seconds. Every failure has the same error shape.

What it does

Reserves a file and says how to send it: one PUT to uploadUrl up to 100 MB, or multipart parts for a larger video (give bytes). Use the id in mediaIds once the file is ready.

Example

bash
curl -X POST 'https://api.flung.dev/v1/media' \  --header "Authorization: Bearer $FLUNG_API_KEY" \  --header 'Content-Type: application/json' \  --header "Idempotency-Key: $(uuidgen)" \  --data '{  "contentType": "image/jpeg"}'

A successful answer looks like this:

json
{  "id": "med_aaaaaaaaaaaaaaaaaaaaaaaa",  "contentType": "image/jpeg",  "filename": "string",  "bytes": 1,  "status": "pending",  "preview": {    "status": "processing",    "thumbnailUrl": "string",    "hlsUrl": "string",    "dashUrl": "string",    "durationSeconds": 1  },  "createdAt": "2026-11-01T09:00:00.000Z"}

Request body

The body has the type an object, with the fields below.

FieldTypeRequiredDescription
contentTypeanyyes
filenamestringnoat least 1 character; at most 255 characters.
bytesintegernoThe file's size. Required over 100 MB, which then uploads in parts. minimum 1.

Responses

StatusMeaningBody
201The reserved file and its upload address.MediaUpload
401Missing, unknown, revoked or expired API key.Error
422The request failed validation.Error
429Too many requests for this credential; wait for retry-after seconds.Error

Response body

A 201 answer has the type MediaUpload.

FieldTypeRequiredDescription
idstringyes
contentTypeMediaTypeyesWhat the file really is, read from its first bytes once uploaded.
filenamestring | nullyes
bytesinteger | nullyes
status"pending" | "processing" | "ready" | "failed"yespending until its bytes arrive; ready once a post can use it.
previewobject | nullyesVideos only, where previews are set up: a thumbnail. Read the file again while processing.
preview.status"processing" | "ready" | "failed" | "skipped"yesskipped when the video is over 100 MB or this month's thumbnail allowance is used up. Posts never wait for a preview; they use the file as uploaded.
preview.thumbnailUrlstring | nullyesA JPEG frame one second in, 640 pixels wide, at an address that does not expire.
preview.hlsUrlstring | nullyesAlways null for now: streaming versions are not made.
preview.dashUrlstring | nullyesAlways null for now.
preview.durationSecondsnumber | nullyesAlways null for now.
createdAtstringyes
uploadUrlstring | nullyesFor a file up to 100 MB: PUT it here, with your credential and its Content-Length. Null for a multipart upload.
multipartobject | nullyesFor a file over 100 MB: how to send it in parts.
multipart.partSizeintegeryesEvery part but the last is exactly this many bytes.
multipart.partCountintegeryes
multipart.partUrlstringyesPUT each part to this address with {partNumber} replaced by 1 to partCount, in any order.
multipart.completeUrlstringyesPOST here once every part is in.

See also

DocWhy
API referenceEvery endpoint
SchemasEvery request and response type
ErrorsEvery error code and what to do about it