Docs › API reference › Videos
Videos API: upload to YouTube or TikTok
Upload a video to one channel with typed settings for its platform, publish it now or later, and poll for the result.
A video goes to one channel at a time, and its settings are typed for that channel's platform. Text posts,
and posts sent to several channels at once, use Posts instead. A video is still a post
underneath (a post with one target), so scheduling, idempotency, limits, cancel and
retry all work the same way.
Publish a video
Upload the file with POST /v1/media first (see Media), then pass its id to
POST /v1/videos:
Leave out scheduledFor to publish now. The answer is 201 with the video. Its id also works on
/v1/groups/{id}, so you can cancel, retry or edit it there.
curl https://omniposts.dev/v1/videos \
-H "Authorization: Bearer omniposts_..." \
-H "Idempotency-Key: tutorial-video-1" \
-H "Content-Type: application/json" \
-d '{
"channelId": "0192a3b4-0000-7000-8000-000000000001",
"mediaId": "0192a3b4-0000-7000-8000-000000000002",
"description": "In this video I show how to post with the OmniPosts API.\n\n0:00 Intro\n1:30 First call",
"scheduledFor": "2026-10-20T09:30:00Z",
"settings": {
"type": "youtube",
"title": "How to post with the OmniPosts API",
"visibility": "private",
"madeForKids": false,
"tags": ["omniposts", "api", "tutorial"],
"format": "video"
}
}'
Request fields
| Field | Type | Meaning |
|---|---|---|
channelId |
id | Required. The channel to upload to. Its platform must match settings.type |
mediaId |
id | Required. A video uploaded with POST /v1/media |
description |
string | The video's description. On YouTube: up to 5,000 bytes, and no < or > |
scheduledFor |
time | When to publish. Leave it out to publish now |
timezone |
string | The time zone the schedule was picked in, for display |
settings |
object | Required. The platform's settings, chosen by settings.type |
YouTube settings
Send these with "type": "youtube". Any other key is refused with a 400, so a typo can't quietly drop a
setting. Each one is a field of YouTube's own upload call
(videos.insert).
| Field | Type | Meaning |
|---|---|---|
type |
youtube |
Required |
title |
string | Required. Up to 100 characters, and no < or > |
visibility |
private, unlisted or public |
Defaults to private. Providers shows whether only private is allowed for now (lockedValue) |
madeForKids |
boolean | Required. Whether the video is made for children, as US law (COPPA) asks. There is no default: it is your declaration, so OmniPosts never makes it for you |
tags |
array of strings | No commas, < or > inside a tag. At most 500 characters in total, counted the way YouTube counts them: a tag with a space counts 2 more (YouTube puts it in quotes), and each comma between tags counts 1 |
categoryId |
string | A YouTube category number. Leave it out to let YouTube decide |
format |
video or short |
Defaults to video. A short must be vertical or square and at most 3 minutes long. OmniPosts checks this before uploading |
notifySubscribers |
boolean | Tell subscribers about the video. Defaults to true |
containsSyntheticMedia |
boolean | Declares realistic content that was altered or made with AI. Defaults to false |
Whether YouTube is open on your account is on Channels.
TikTok settings
Send these with "type": "tiktok", for a TikTok or a TikTok for Business channel. TikTok has no separate
video title: the request's description is the caption, up to 2,200 characters, with emoji counting as two.
Any other key is refused with a 400.
| Field | Type | Meaning |
|---|---|---|
type |
tiktok |
Required |
mode |
direct |
Optional. For a draft, see TikTok drafts |
privacyLevel |
PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR or SELF_ONLY |
Required, with no default: TikTok asks that the person choose who sees each video. Providers shows whether only SELF_ONLY is allowed for now (lockedValue). TikTok for Business channels publish videos to everyone, so they take only PUBLIC_TO_EVERYONE |
disableComment |
boolean | Turn off comments. Defaults to false |
disableDuet |
boolean | Turn off Duet. Defaults to false |
disableStitch |
boolean | Turn off Stitch. Defaults to false |
commercialContent |
boolean | The disclosure switch: the video promotes a brand, product or service. When true, set brandedContent, yourBrand or both to true, or the request is refused with a 400. Defaults to false |
brandedContent |
boolean | A paid partnership: the video promotes another brand in exchange for something of value. TikTok labels it "Paid partnership". It cannot be SELF_ONLY. Defaults to false |
yourBrand |
boolean | The video promotes your own business. TikTok labels it "Promotional content". Defaults to false |
aiGenerated |
boolean | Label the video as AI-generated. Defaults to false |
coverTimestampMs |
whole number | TikTok channels only: the frame to use as the cover, in milliseconds from the start. Leave it out for the first frame |
Right before it posts, OmniPosts reads the account's current settings from TikTok. The video fails, with
failure saying why, when privacyLevel is not one this account offers or the video is longer than the
account may post. Comments, Duet or Stitch that the creator turned off in TikTok stay off, whatever you send.
TikTok downloads the video from OmniPosts and then processes it, so the video stays awaiting_platform for a
minute or more before it is published. A video only you can see has no public link, so its externalUrl
stays empty.
{
"channelId": "0192a3b4-0000-7000-8000-000000000003",
"mediaId": "0192a3b4-0000-7000-8000-000000000002",
"description": "Glazing day, start to finish #pottery",
"settings": {
"type": "tiktok",
"privacyLevel": "SELF_ONLY",
"disableDuet": true,
"aiGenerated": false
}
}
TikTok drafts
Send "mode": "draft" to put the video in the creator's TikTok inbox instead of posting it. TikTok
notifies them, and they add the caption and settings and post it from the TikTok app.
- A draft carries only the video. Leave out
descriptionand every other setting, or the request is refused with a400, because TikTok would drop them. - Drafts work for TikTok channels, not TikTok for Business ones.
- The video is
publishedonce it is in the inbox. It has noexternalUrl, because nothing is public yet. - TikTok allows 5 pending drafts from apps per account in 24 hours. Past that the video fails with
pending_draft_cap. - The channel needs permission to upload drafts. A TikTok channel connected before OmniPosts asked for it
fails with
draft_permission_missinguntil it is reconnected.
{
"channelId": "0192a3b4-0000-7000-8000-000000000003",
"mediaId": "0192a3b4-0000-7000-8000-000000000002",
"settings": { "type": "tiktok", "mode": "draft" }
}
GET /v1/videos/{id}
Follow a video
GET /v1/videos/{id} returns the video. Its status is the status of the upload itself
(post statuses). When it is published, externalUrl links to the video;
when it is failed or unknown, failure says what happened and what to do. You can also subscribe to
webhooks and skip polling. A post sent to several channels is not a video, and this
endpoint answers 404 for it.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request |
A missing field, an unknown settings.type, an unknown settings key, or a value of the wrong kind |
| 404 | not_found |
The channel is not one of yours, or it was disconnected |
| 409 | idempotency_conflict |
The same Idempotency-Key was used for a different request |
| 422 | settings_type_mismatch |
The settings are for a different platform than the channel's. details has settingsType and providerId |
| 422 | nothing_to_publish |
The platform's rules refuse the video before it is sent, for example an image instead of a video. details.rejections[0].failure says why |
Plan and posting limits answer the same way as for posts. See Errors for the envelope.