Skip to content
Sign in Waitlist
Docs/Guides/Upload media: single file and parts

Upload media: single file and parts

Every video, cover and photo goes through /v1/media before it can be used in a post. There are two paths, depending on size.

Single file In parts
When Up to 50 MiB Any size (video up to 5 GiB)
How to create POST /v1/media with simple: true POST /v1/media without simple
How to upload PUT /v1/media/:id/content with the bytes PUT /v1/media/:id/parts/:part for each part
How to finish The PUT itself completes it POST /v1/media/:id/complete

Accepted types and sizes

Type (`type`) Accepted `mime` Maximum size
video video/mp4, video/quicktime 5 GiB
cover image/png, image/jpeg 20 MiB
image image/jpeg (JPEG only) 20 MiB

image is the photo of an image post. The server checks that the file really is a JPEG (422 invalid_image if not: on a single upload, before storing; on a multipart upload, on complete) and reads the width and height from the header (width and height on the media item). It does not convert: export the photo as sRGB JPEG (Praeko Studio does that).

A single photo on Instagram

Upload the photo with type: image and create the post with kind: image and one image in media.images (several would be a carousel, which does not exist yet: 422 carousel_not_supported). Only Instagram takes a photo for now, through Buffer or directly through Meta; YouTube and TikTok answer 422 kind_not_supported_by_network.

json
{
  "kind": "image",
  "title": "Tip: small PRs",
  "media": {
    "images": [
      {
        "media": "01KA3V9...",
        "alt": "Slide with the title of the tip"
      }
    ]
  },
  "texts": {
    "instagram": {
      "text": "One PR, one idea. #devbrasil"
    }
  },
  "items": [
    {
      "network": "instagram",
      "via": "meta",
      "queue": true
    }
  ]
}
Instagram rule Value If not met
Format JPEG 422 invalid_image
Size 8 MB 422 image_too_large
Aspect ratio from 4:5 to 1.91:1 (use 1080x1350) 422 image_aspect_ratio
Width 320 to 1440 px (Meta upscales or downsizes the rest) warning image_small or image_will_be_resized
Caption up to 2200 characters and 30 hashtags 422 invalid_field
Alt text (alt) up to 1000 characters through Buffer it is ignored: warning alt_ignored

Warnings come back in items[].warnings (each with a stable code and message) and do not stop the creation. Through Meta the alt goes in the photo container; through Buffer, which has no documented alt text, it is ignored and the item warns. The post comes back with kind and media.images; the image of an image post cannot be replaced by PATCH (cancel and create again).

Single file

curl
curl -X POST https://praeko.app/v1/media \
  -H "Authorization: Bearer $PRAEKO_KEY" -H "X-Praeko-Contract: en" \
  -H "Content-Type: application/json" \
  -d '{ "type": "video", "name": "v.mp4", "mime": "video/mp4", "size": 8123456, "simple": true }'
curl -X PUT https://praeko.app/v1/media/$MEDIA_ID/content \
  -H "Authorization: Bearer $PRAEKO_KEY" -H "Content-Type: video/mp4" \
  --data-binary @v.mp4

With simple: true and a size above 50 MiB, creation is rejected (422 file_too_large): use parts. The PUT body must be exactly the agreed size (422 size_mismatch).

Multipart upload

The POST /v1/media response (without simple) has minPartSize (5 MiB), maxPartSize (95 MiB) and suggestedPartSize (16 MiB). Number the parts from 1 to 10000, send each one with PUT /v1/media/:id/parts/:part as raw bytes, and finish with POST /v1/media/:id/complete.

curl
# 16 MiB per part; the last one takes the rest
split -b 16m v.mp4 part_
n=1; for f in part_*; do
  curl -X PUT "https://praeko.app/v1/media/$MEDIA_ID/parts/$n" \
    -H "Authorization: Bearer $PRAEKO_KEY" -H "Content-Type: video/mp4" \
    --data-binary @"$f"
  n=$((n+1))
done
curl -X POST https://praeko.app/v1/media/$MEDIA_ID/complete \
  -H "Authorization: Bearer $PRAEKO_KEY" -H "X-Praeko-Contract: en"

State and use

Media starts as uploading and becomes ready when the upload finishes. ready videos carry durationMs, width and height when the file header provides them (older videos get them on first read), and GET /v1/media/:id also returns publicUrl. Only use ready media in a post (otherwise 409 media_not_ready). DELETE /v1/media/:id refuses media used by a pending post (409 media_in_use).

durationMs is the duration in milliseconds read from the file. Do not confuse it with duration in GET /v1/youtube/videos, which is the duration YouTube reports, in ISO 8601 (for example, PT58S).

With the SDK or an agentuploadFile from @praeko/sdk/node sends a file from disk and picks the path for you (one PUT up to 32 MiB; above that, 16 MiB parts): SDK. An agent with a shell uses the create_media_upload and complete_media_upload tools of the MCP server.
Question or mistake on this page? contato@praeko.appView .md

Type to search pages, routes and error codes.