Video Actions – Publish, Finalize & Corrections
Take actions on TokPortal videos via API. Publish, finalize, request corrections, unschedule, and reset video slots.
Video Actions
These endpoints let you take actions on individual videos within a bundle — publish, finalize, request corrections, or unschedule.
Publish a Video
Publish a single configured video on an already-active bundle. Use this after adding new video slots to an accepted bundle, configuring them, and wanting the account manager to start working on them.
POST /bundles/:id/videos/:position/publish
The bundle must be in published, published_priority, or accepted status. The video must be in configured status.
curl -X POST https://app.tokportal.com/api/ext/bundles/{id}/videos/3/publish \
-H "X-API-Key: sk_xxx"
Response:
{
"data": {
"video_id": "uuid",
"position": 3,
"bundle_id": "uuid",
"status": "published"
}
}
If the target date went stale
A slot can sit configured until its target_publish_date reaches today. Publishing does not reject that — it moves the slot forward to the earliest allowed day and tells you it did:
{
"data": {
"video_id": "uuid",
"position": 3,
"bundle_id": "uuid",
"status": "published",
"date_adjusted": true,
"original_date": "2026-08-24",
"new_date": "2026-08-27",
"hint": "The earliest target date in this batch was already today or in the past at publish time, so the whole batch was shifted forward by the same number of days — original pacing, gaps and order are preserved. Use PATCH /bundles/{id}/videos/{position} to reschedule."
}
}
| Field | Type | Description |
|---|---|---|
date_adjusted | boolean | Present only when the date was moved. Absent means the schedule you sent survived untouched. |
original_date | string | The stale date the slot carried, YYYY-MM-DD. |
new_date | string | The day it was moved to, YYYY-MM-DD. |
hint | string | What happened and how to change it. |
INFO: These four fields were documented long before they existed Until 2026-08-26 the underlying procedure never returned them and the slot published on its stale date, landing in the manager's calendar as instantly-due work. They are real now.
Publish All Configured Videos
Publish all configured videos on a bundle at once. Useful after batch-configuring multiple new slots.
POST /bundles/:id/videos/publish-all
curl -X POST https://app.tokportal.com/api/ext/bundles/{id}/videos/publish-all \
-H "X-API-Key: sk_xxx"
Response:
{
"data": {
"bundle_id": "uuid",
"videos_published": 3,
"video_ids": ["uuid1", "uuid2", "uuid3"]
}
}
Stale dates are moved forward, not rejected
If the earliest target date in the call has already reached today or the past, the whole set slides forward by the same number of days before publishing — pacing, gaps and order are preserved. If the earliest date is still in the future, nothing moves. The publish never fails because of the adjustment.
The move respects the 3 videos per day per bundle cap: if the earliest allowed day is already full, the slot spills to the next day, and so on.
{
"data": {
"bundle_id": "uuid",
"videos_published": 3,
"video_ids": ["uuid1", "uuid2", "uuid3"],
"dates_adjusted": 2,
"adjusted_videos": [
{ "video_id": "uuid1", "position": 1, "previous_date": "2026-08-24", "new_date": "2026-08-27" },
{ "video_id": "uuid2", "position": 2, "previous_date": "2026-08-25", "new_date": "2026-08-27" }
],
"hint": "The earliest target date in this batch was already today or in the past at publish time, so the whole batch was shifted forward by the same number of days — original pacing, gaps and order are preserved. Use PATCH /bundles/{id}/videos/{position} to reschedule."
}
}
| Field | Type | Description |
|---|---|---|
dates_adjusted | integer | How many slots were moved. Present only when at least one was. |
adjusted_videos | array | One entry per moved slot: { video_id, position, previous_date, new_date }. |
hint | string | What happened and how to change it. |
WARNING:
earliest_allowed_dateno longer exists on this response It was documented but never returned.adjusted_videosreplaces it and is strictly more useful: a single "earliest allowed" day could not describe a set of slots that were spread over several days by the per-day cap. If your integration readsearliest_allowed_date, readadjusted_videos[].new_dateinstead.
TIP: Typical workflow for adding videos to an active bundle
POST /bundles/:id/add-video-slots— Add new slots (credits debited)PUT /bundles/:id/videos/batch— Configure the new videosPOST /bundles/:id/videos/publish-all— Publish them so the manager can start
Finalize a Video
POST /bundles/:id/videos/:position/finalize
Marks a video as finalized, completing its lifecycle. Once finalized, no further changes can be made to the video.
A video can only be finalized when its current status is in_review.
WARNING: 72-hour review window Delivered work sits in review and auto-finalizes about 72 hours (72h01) after the video listing enters
in_review. If you do not finalize the video or request corrections during that window, TokPortal changes its status tofinalizedon its own. Once finalized, no further corrections can be requested and the manager's payout is released.This happens regardless of
auto_finalize_videos— that flag does not switch automatic finalization off. If you need control over a delivery, act inside the window with this endpoint or with Request Corrections.
curl -X POST https://app.tokportal.com/api/ext/bundles/bundle_abc123/videos/1/finalize \
-H "X-API-Key: sk_xxx"
Response:
{
"data": {
"video_id": "uuid",
"position": 1,
"bundle_id": "bundle_abc123",
"status": "finalized"
}
}
Error — invalid status transition:
{
"error": {
"code": "VIDEO_INVALID_STATUS",
"message": "This video is not in a valid status for this action.",
"details": {
"current_status": "configured",
"required": "in_review"
}
}
}
Request Corrections
POST /bundles/:id/videos/:position/corrections
Sends the video back to the account manager with correction instructions. The video must currently be in_review; its status becomes pending_corrections.
Corrections can only be requested inside the 72-hour review window described above, which closes regardless of auto_finalize_videos.
| Field | Type | Required | Description |
|---|---|---|---|
comment | string | Yes | Instructions describing what needs to be changed (1-2,000 characters). |
fields | object | No | Boolean flags for the affected areas: video_content, description, video_editing, and/or sound. Omitted fields are not flagged. |
curl -X POST https://app.tokportal.com/api/ext/bundles/bundle_abc123/videos/2/corrections \
-H "X-API-Key: sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"comment": "Sound only: replace the current sound with the official campaign track. Do not change the video or caption.",
"fields": {
"sound": true
}
}'
Response:
{
"data": {
"video_id": "uuid",
"position": 2,
"bundle_id": "bundle_abc123",
"status": "pending_corrections"
}
}
Unschedule a Video
POST /bundles/:id/videos/:position/unschedule
Reverts a video back to configured status (cancels scheduling). Works on published, configured, or accepted videos.
curl -X POST https://app.tokportal.com/api/ext/bundles/bundle_abc123/videos/3/unschedule \
-H "X-API-Key: sk_xxx"
Response:
{
"data": {
"video_id": "uuid",
"position": 3,
"bundle_id": "uuid",
"status": "configured"
}
}
Error — invalid status:
{
"error": {
"code": "VIDEO_INVALID_STATUS",
"message": "Invalid video status for this action.",
"details": {
"current_status": "finalized",
"allowed": ["published", "configured", "accepted"],
"hint": "Only published, configured, or accepted videos can be unscheduled."
}
}
}
Reset a Video
POST /bundles/:id/videos/:position/reset
Clears all configuration from a video slot — description, URL, dates, sound, editing instructions, and all platform-specific fields — returning it to a blank state. The slot itself is preserved and can be reconfigured with PUT /bundles/:id/videos/:position.
Only works on pending or configured videos. If a video is published or accepted, use unschedule first, then reset.
curl -X POST https://app.tokportal.com/api/ext/bundles/bundle_abc123/videos/3/reset \
-H "X-API-Key: sk_xxx"
Response:
{
"data": {
"video_id": "uuid",
"position": 3,
"bundle_id": "uuid",
"status": "configured",
"message": "Video has been reset to blank state. You can reconfigure it with PUT /bundles/:id/videos/:position."
}
}
Error — invalid status:
{
"error": {
"code": "VIDEO_INVALID_STATUS",
"details": {
"current_status": "accepted",
"allowed": ["pending", "configured"],
"hint": "Only pending or configured videos can be reset. Use unschedule first if the video is published or accepted."
}
}
}
TIP: To fully clear a published or accepted video
POST /bundles/:id/videos/:position/unschedule— reverts toconfiguredPOST /bundles/:id/videos/:position/reset— clears all configuration
Action Summary
| Action | Endpoint | Allowed From Status | Result Status |
|---|---|---|---|
| Publish | POST .../publish | configured | published |
| Finalize | POST .../finalize | in_review | finalized |
| Corrections | POST .../corrections | in_review | pending_corrections |
| Unschedule | POST .../unschedule | published, configured, accepted | configured |
| Reset | POST .../reset | pending, configured | (blank, same status) |
| Fix Download | POST .../fix-download | any (requires download_issue: true) | (same status, issue cleared) |
See also: Fix Download Link for full details on detecting and fixing broken links.