Publish a video end to end
The full path, from a file on disk to an item published on the network. Every step links to its route in the reference.
/v1/media)./v1/posts).Check your channels
GET /v1/channels lists the connected channels and how many time slots each one has. Connect networks in the panel, under Channels; an entry with connected: false is not connected yet.
curl https://praeko.app/v1/channels \
-H "Authorization: Bearer $PRAEKO_KEY" -H "X-Praeko-Contract: en"Upload the video
POST /v1/media creates the media. Up to 50 MiB, with simple: true, send the whole file with PUT /v1/media/:id/content. Above that, upload in parts: see Upload media.
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 }'
# response: { "id": "…", "state": "uploading", … }
curl -X PUT https://praeko.app/v1/media/$MEDIA_ID/content \
-H "Authorization: Bearer $PRAEKO_KEY" -H "Content-Type: video/mp4" \
--data-binary @v.mp4Create the post
A post has one item per network. Each item takes the channel's next free slot (queue: true), a fixed time (scheduledFor, ISO 8601 UTC) or stays a draft (draft: true). Each network's text goes in texts. mode sets the visibility: YouTube private, scheduled or public; TikTok draft or direct; Instagram now.
curl -X POST https://praeko.app/v1/posts \
-H "Authorization: Bearer $PRAEKO_KEY" -H "X-Praeko-Contract: en" \
-H "Content-Type: application/json" \
-d '{ "title": "My video",
"media": { "video": "'$MEDIA_ID'" },
"texts": { "youtube": { "text": "Description" }, "tiktok": { "text": "Caption" } },
"items": [
{ "network": "youtube", "queue": true },
{ "network": "tiktok", "scheduledFor": "2026-11-10T20:30:00Z" }
] }'The response is 201 with the post id and one item per network, each with state and scheduledFor.
Check the result
GET /v1/posts/:id returns the post with its items. An item's state is draft, scheduled, sent, private (on YouTube: uploaded as private, waiting for you), error or canceled. Instead of polling, register a webhook: post.sent tells you when it went out and post.failed when the item gave up.
After you create it
| I want to | Route |
|---|---|
| Change the title, text or time, or move it to drafts | PATCH /v1/posts/:id |
| Publish a queued item now | POST /v1/posts/:id/publish-now |
| Cancel the pending items | DELETE /v1/posts/:id |
| See what is scheduled and the free slots | GET /v1/calendar |
PATCH /v1/posts/:id can still change the time (at least 5 minutes ahead), the title, the description and the pinned comment, checking the video live; the response has itemResults per item. A video that is already public returns 409 video_not_private; a time that has passed, 409 not_editable. Canceling with DELETE does not hold that video back: YouTube publishes it on schedule. Use ?dismiss=true to remove the publish time (it stays private) or ?dismiss=true&delete_video=true to delete it.409 media_locked; deleting media used by a pending post returns 409 media_in_use.Idempotency-Key header and the retry gets the first response without creating another post: see how. Without the header, send your own id (a repeat returns 409 id_exists).