Videos
Video management in the TokPortal API. Video types, statuses, supported formats for TikTok and Instagram content.
Videos
Videos are the content units within a bundle. Each video occupies a specific position (1-indexed) in the bundle and represents a single piece of content to be published on a creator's social media account.
Video Types
Every video has a video_type that determines what content it contains:
| Type | Description |
|---|---|
video | A single video file |
carousel | Multiple images displayed as a slideshow |
story | A TikTok/Instagram Story — one video or one image, no description. Counts as one video slot and is verified by an account-manager screenshot (evidence_screenshot). See Configure Videos → Story Fields. |
Platform-Specific Behavior
Each platform supports different combinations of video types and has its own requirements.
TikTok
| Type | Requirements |
|---|---|
video | Video file required. Sound URL optional. |
carousel | Carousel images required. Sound URL required. |
story | Exactly one media: video_url or story_image_url. No description. Optional same-platform story_repost_url (+1 credit). |
Instagram requires the instagram_content_type field to distinguish between reels and feed posts:
| Content Type | Video Type | Result |
|---|---|---|
reel | video | Reel Video |
reel | carousel | Reel Fixed Photos — creates a video from images (not swipeable) |
post | video | Post Video |
post | carousel | Post Carousel — swipeable photo carousel |
INFO: Reel Fixed Photos vs Post Carousel On Instagram,
video_type: "carousel"behaves differently depending oninstagram_content_type:
- With
"reel": Instagram creates a video from your images (Fixed Photos — not swipeable). This is a Reel, not a carousel.- With
"post": Instagram creates a swipeable photo carousel in the feed.
Instagram also supports video_type: "story" (one video or one image, no instagram_content_type). See Configure Videos → Story Fields.
YouTube
YouTube accounts cannot be ordered through the API. Public bundle creation supports TikTok and Instagram only, and a YouTube bundle is rejected with YOUTUBE_DELAYED — even though GET /credit-costs lists a YouTube price, the price is real but the order path is not open. YouTube accounts are delivered through a separate, non-API flow; talk to the team. You may still see reserved YouTube fields in templates and generated schemas.
Video Status Lifecycle
Each video progresses through the following statuses:
pending → configured → published → accepted → in_review → finalized
| Status | Description |
|---|---|
pending | Position exists but no content has been configured yet. |
configured | Content has been uploaded and metadata set. Ready for review. |
published | The video has been published to the platform by the creator. |
accepted | The brand has reviewed and accepted the published video. |
in_review | The video is awaiting client review. Ordinary reviews auto-finalize after about 72 hours; inconclusive TikTok sound reviews require an explicit client decision (see below). |
finalized | The video lifecycle is complete, either after user approval or automatic finalization at the end of the 72-hour review window. No further changes are allowed. |
The 72-hour window starts when the video listing enters in_review. Inconclusive TikTok sound checks are an exception: they require an explicit client review and never finalize automatically, as explained below. Finalize it to approve it immediately, or request corrections before the window expires. If neither action is taken, finalization is automatic — this applies regardless of auto_finalize_videos, which does not switch automatic finalization off.
TikTok sound verification
For manager-published TikTok videos and carousels with a requested sound, TokPortal checks the attached sound ID. Original and added audio levels are checked only when volume instructions were supplied. An unavailable metadata read is not proof of a wrong sound or an unavailable sound.
| Situation | Result | Your next action |
|---|---|---|
| A post URL was submitted, but automatic sound or volume verification remains inconclusive | The existing post enters in_review, with review_required: true in the video.in_review webhook. | Inspect the submitted post, then finalize or request corrections. |
| The manager reports that the requested sound cannot be used or is restricted in the account country | The video returns to configured. You receive a dashboard notification, an email if enabled, and video.configured with reason: "sound_unavailable". | Choose another sound, set a valid publication window and publish the configured task again. |
| Automatic verification positively detects the wrong attached sound or an out-of-tolerance requested volume | The manager corrects the existing task through the normal correction flow. | No action is required unless another sound must be chosen. |
Inconclusive sound reviews are never automatically approved, including after the usual 72-hour review period and when auto_finalize_videos is enabled. The client can approve or request corrections directly; no separate staff approval is required. The original post URL and submission timestamp are retained, and the manager can continue other tasks.
An unavailable-sound report needs no screenshot or routine staff review. The return to configured is a request for your new instructions, not an approval of a substitute post. Its webhook includes:
sound_unavailable_reason:unavailable_for_useorcountry_restricted;restriction_verified:truefor verified restriction evidence,falsewhen the manager reported the restriction and automatic verification could not confirm it;requested_sound_urlandsound_report_idfor the affected instructions.
A manager declaration is never reused as verified evidence for another task or account. No alternative recording is selected without your instructions. Existing post references remain reserved, so this workflow does not create duplicate publications or bypass checks on earlier public copies.
Subscribe to both video.in_review and video.configured. Their event IDs are stable across delivery retries; deduplicate by the envelope's id.
Volume instructions keep the API's existing 0–200 scale. No client input is rewritten. A missing volume instruction skips volume comparison only; it does not skip the requested sound ID check.
Platform Signals
Once a video is live, TokPortal checks what the platform did with it: about 48 hours after posting and again after 7 days, plus whenever the post is scraped for analytics. The result is returned on every video as platform_signals, also on the order progress page and in Analytics. The object is always present; every field is null until the first check — null means not checked yet, never no.
"platform_signals": {
"checked_at": "2026-09-22T05:47:52Z",
"not_recommended": true,
"not_recommended_since": "2026-09-19T05:28:00Z",
"ai_label": null,
"sound": "non_commercial",
"sound_reason": "Can't promote due to audio copyright issue"
}
| Field | Type | Description |
|---|---|---|
checked_at | string | null | Last time the live post was observed. |
not_recommended | boolean | null | TikTok Not For Feed / Not Recommended. true = the post stays online but is excluded from the For You feed and typically sits at 0 views. Usually a sign that TikTok treats the content as reused across accounts or low-effort. Re-posting the same media does not help; new original content on the account does. |
not_recommended_since | string | null | First observation of the flag. |
ai_label | creator | platform | null | An "AI-generated" label is shown on the post: creator = declared at posting time, platform = applied by TikTok's moderation on its own. |
sound | ok | non_commercial | removed | muted | null | non_commercial: the sound is outside TikTok's commercial music library — the post cannot be boosted with Promote / Spark Ads. removed: TikTok pulled the sound for copyright, the video plays muted. muted: Instagram muted the audio. |
sound_reason | string | null | Platform wording when the sound is restricted. |
The same observations are pushed as webhooks the moment they are detected: video.not_recommended, video.ai_labeled and video.sound_restricted. Portfolio-wide, GET /analytics/signals lists every flagged post.
Publish Date Rules
The target_publish_date field controls when the video should be published.
- Account still being created (not yet delivered): minimum 3 days from today.
- Account already delivered, or a bundle running on an existing account: minimum 1 day from today.
A bundle can also carry at most 3 videos targeting the same day. Dates earlier than the allowed minimum are rejected with a VALIDATION_ERROR.
List All Videos in a Bundle
Retrieve every video configured for a bundle.
GET /bundles/:id/videos
curl -X GET https://app.tokportal.com/api/ext/bundles/bundle_abc123/videos \
-H "X-API-Key: sk_xxx"
Response:
{
"data": [
{
"position": 1,
"video_type": "video",
"status": "configured",
"description": "Unboxing the new product line",
"target_publish_date": "2026-03-15",
"video_url": "https://pub-xxx.r2.dev/videos/abc123.mp4",
"external_ref": "campaign-42-v1",
"download_issue": false,
"download_issue_comment": null
},
{
"position": 2,
"video_type": "carousel",
"status": "pending",
"description": null,
"target_publish_date": null,
"video_url": null,
"external_ref": null,
"download_issue": false,
"download_issue_comment": null
}
]
}
Get a Single Video
GET /bundles/:id/videos/:position
curl -X GET https://app.tokportal.com/api/ext/bundles/bundle_abc123/videos/1 \
-H "X-API-Key: sk_xxx"
Response:
{
"data": {
"position": 1,
"video_type": "video",
"status": "configured",
"description": "Unboxing the new product line",
"target_publish_date": "2026-03-15",
"video_url": "https://pub-xxx.r2.dev/videos/abc123.mp4",
"tiktok_sound_url": "https://www.tiktok.com/music/original-sound-123",
"editing_instructions": "Add brand logo at the end",
"external_ref": "campaign-42-v1",
"download_issue": false,
"download_issue_comment": null,
"platform_signals": {
"checked_at": null,
"not_recommended": null,
"not_recommended_since": null,
"ai_label": null,
"sound": null,
"sound_reason": null
}
}
}
What's Next
| Topic | Description |
|---|---|
| Configure Videos | Set content, metadata, and platform-specific fields |
| Patch Video Metadata | Update external_ref or name at any time without re-uploading content |
| CSV Import | Bulk-import videos from a CSV file |
| Video Actions | Finalize, request corrections, or unschedule videos |
| Fix Download Link | Detect and fix broken download links flagged by managers |