REST API

Media

Three calls to attach an image.

Files go straight from you to storage. They never pass through our API, so a large upload does not sit in a request.

POST/v1/media/presign

Ask for an upload URL and a media id.

NameTypeDescription
fileNameRequiredstringOriginal file name.
contentTypeRequiredstringimage/jpeg, image/png
bytesRequirednumberFile size in bytes.
widthnumberPixel width, if you know it.
heightnumberPixel height, if you know it.
altTextstringWhat the image shows, for screen readers. Applied to carousel items.

What comes back

NameTypeDescription
idstringPass this to publish as a mediaId.
uploadUrlstringOne-time PUT target.
contentTypestringSend exactly this on the PUT.
expiresInnumberSeconds the uploadUrl stays valid.
mediaExpiresAtstringISO 8601. After this the media id is reclaimed if it was never published.
# 1. ask for a slot
curl -X POST https://api.uplika.com/v1/media/presign \
  -H "authorization: Bearer $UPLIKA_KEY" \
  -H "content-type: application/json" \
  -d '{"fileName":"cover.jpg","contentType":"image/jpeg","bytes":184320,"altText":"A cat on a windowsill"}'
# -> { "id": "med_01H...", "uploadUrl": "https://...", "mediaExpiresAt": "2026-08-12T..." }

# 2. send the bytes straight to storage (no auth header)
curl -X PUT "$UPLOAD_URL" -H "content-type: image/jpeg" --data-binary @cover.jpg

# 3. confirm
curl -X POST https://api.uplika.com/v1/media/med_01H.../complete \
  -H "authorization: Bearer $UPLIKA_KEY"

Upload the bytes

PUT the file to the uploadUrl with the same Content-Type you declared. No auth header. The URL is already signed and it expires.

POST/v1/media/{id}/complete

Confirm the upload. We check the object really exists.

What if the file is already on the web?

Agents without a shell cannot PUT bytes, so the three step upload is out of reach for them. Give us the URL instead and we download the file, copy it into our storage and hand back a media id. We never pass someone else’s URL on to the channel. https only, and Google Drive or Dropbox share links do not work because they return an HTML preview instead of the file.

POST/v1/media/from-url

Copy a public file into your workspace in one call.

NameTypeDescription
urlRequiredstringPublic https URL of the file itself.
altTextstringWhat the image shows, for screen readers.

What we accept

NameTypeDescription
typesimageimage/jpeg, image/png
sizeimageup to 8MB
aspect ratioimageup to 10:1 (any pixel width)
countimageup to 20 per post on Threads
typesvideovideo/mp4, video/quicktime
sizevideoup to 2048MB
lengthvideoup to 43200 seconds
widthvideoup to 3840px
carouselmixed2-20 items on Threads, images and video can be mixed

Common questions

How many calls does one image take?

Three. Presign for an id and an upload URL, PUT the bytes to that URL, then complete to confirm. Only after the third can publish use the id.

Does the file go through your API?

No. It goes straight from you to storage on a signed URL, so a large upload never sits inside one of our requests.

Can I put an image and a video in the same post?

On Threads, yes, in a carousel of two to twenty items. Channels that do not allow it refuse with media_mixed, and the limits endpoint tells you which is which per channel.