Video Editor
Create editable videos, upload media, add clips, and apply edits.
The editor API lets you create editable videos, upload media, add existing media to a timeline, and apply direct edits.
Editor videos created through this API use status: "ready" because ready means the editor project exists and can be opened. Exporting or downloading an MP4 is a separate action.
POST /editor/videos
Creates an editable project that is ready to open immediately.
Requires generations:write.
curl -X POST https://videotok.app/api/v1/editor/videos \
-H "Authorization: Bearer vt_live_..." \
-H "Content-Type: application/json" \
-d '{
"title": "TikTok ad draft",
"aspect_ratio": "9:16",
"fps": 30
}'
GET /editor/videos
Lists editable videos.
Requires generations:read or generations:write.
curl https://videotok.app/api/v1/editor/videos \
-H "Authorization: Bearer vt_live_..."
GET /editor/videos/{id}
Returns one editable video.
Requires generations:read or generations:write.
curl https://videotok.app/api/v1/editor/videos/1234 \
-H "Authorization: Bearer vt_live_..."
POST /editor/media/upload-url
Prepares a direct upload for a local file without sending its bytes through the hosted API. Requires generations:write. Use this for files above the 3 MiB inline/multipart limit.
curl -X POST https://videotok.app/api/v1/editor/media/upload-url \
-H "Authorization: Bearer vt_live_..." \
-H "Content-Type: application/json" \
-d '{
"filename": "render.mp4",
"content_type": "video/mp4",
"size_bytes": 8388608
}'
Pass the actual file size in bytes. Video files may be up to 200 MiB; image/audio files up to 50 MiB. The response contains upload.method (PUT), upload.url, upload.headers, and source_url.
From the machine holding the file, PUT the raw bytes to the returned upload.url using upload.headers. For example, replacing the placeholder with that URL:
curl -X PUT 'RETURNED_UPLOAD_URL' \
-H 'Content-Type: video/mp4' \
--data-binary @/path/to/render.mp4
Do not send multipart data or your Videotok API key to the storage URL. After the PUT succeeds, import the returned source_url with POST /editor/media:
{
"source_url": "RETURNED_SOURCE_URL",
"filename": "render.mp4",
"content_type": "video/mp4",
"media_type": "video",
"preserve_original": true
}
Preparation and PUT alone do not create a My Media item. The import returns its media.id. With MCP, the equivalent is prepare_editor_media_upload, then a local PUT, then upload_editor_media_from_url with url set to the returned source_url.
Use preserve_original: true only for an MP4/WebM already checked for playback and destination compatibility. It skips video transcoding, preserves the source codec/container, and does not generate a thumbnail or validate codec compatibility. Omit it for the default Stream transcoding flow. Downloads and storage transfers can still fail or time out.
POST /editor/media
Uploads media to the workspace media library.
It can also add the uploaded media directly to an editor video.
Requires generations:write.
Use one upload source per request:
| Source | When to use it |
|---|---|
media | Inline base64 or data URL; decoded file size at most 3 MiB. |
source_url | HTTPS URL that Videotok imports into My Media. Video limit: 200 MiB; image/audio: 50 MiB. Use after direct upload for larger local files. |
multipart file | Local image, video, or audio file at most 3 MiB with multipart/form-data. |
Hosted APIs cannot read a local file:// path directly. Use inline base64 or multipart for files at most 3 MiB; for larger files, use the direct upload flow above or an existing HTTPS source_url.
Inline JSON:
curl -X POST https://videotok.app/api/v1/editor/media \
-H "Authorization: Bearer vt_live_..." \
-H "Content-Type: application/json" \
-d '{
"media_type": "image",
"title": "Product image",
"video_id": 1234,
"add_to_editor": true,
"media": {
"filename": "product.png",
"content_type": "image/png",
"data": "iVBORw0KGgo..."
},
"placement": {
"from_seconds": 0,
"duration_seconds": 4,
"fit": "cover"
}
}'
Remote URL:
curl -X POST https://videotok.app/api/v1/editor/media \
-H "Authorization: Bearer vt_live_..." \
-H "Content-Type: application/json" \
-d '{
"media_type": "video",
"title": "Hyperframes export",
"source_url": "https://files.example.com/hyperframes-export.mp4",
"filename": "hyperframes-export.mp4"
}'
Local file (at most 3 MiB):
curl -X POST https://videotok.app/api/v1/editor/media \
-H "Authorization: Bearer vt_live_..." \
-F "media_type=video" \
-F "title=Hyperframes export" \
-F "file=@/path/to/hyperframes-export.mp4"
The response includes a completed My Media media.id. Use that id with publish_media_to_social, POST /editor/videos/{id}/media, or generation media-id fields such as source_video_media_id.
GET /editor/media
Lists media available to the editor.
Requires generations:read or generations:write.
| Parameter | Notes |
|---|---|
media_type | image, video, audio, or voice. audio includes voice assets; use voice for voice-only. |
query | Searches filename and indexed text. |
limit | 1 to 100. Default is 30. |
curl "https://videotok.app/api/v1/editor/media?media_type=image&limit=20" \
-H "Authorization: Bearer vt_live_..."
POST /editor/videos/{id}/media
Adds existing media or a direct URL to an editor timeline.
Use from_seconds for timeline placement, duration_seconds for visible timeline length, and source_start_seconds when trimming into a source video or audio file.
Requires generations:write.
curl -X POST https://videotok.app/api/v1/editor/videos/1234/media \
-H "Authorization: Bearer vt_live_..." \
-H "Content-Type: application/json" \
-d '{
"media_id": "0c2796d2-43ef-4e13-b1d4-4187696929d6",
"from_seconds": 0,
"duration_seconds": 5,
"fit": "cover"
}'
Direct URL:
{
"url": "https://example.com/clip.mp4",
"media_type": "video",
"filename": "clip.mp4",
"duration_seconds": 8,
"from_seconds": 0,
"fit": "cover"
}
PATCH /editor/videos/{id}
Applies direct edits.
Requires generations:write.
curl -X PATCH https://videotok.app/api/v1/editor/videos/1234 \
-H "Authorization: Bearer vt_live_..." \
-H "Content-Type: application/json" \
-d '{
"instructions": "Move the product image later and rename the project.",
"operations": [
{
"type": "set_title",
"title": "Final TikTok ad"
},
{
"type": "set_item_timing",
"item_id": "item_abc",
"from_seconds": 1.5,
"duration_seconds": 4
}
]
}'
Supported Edit Operations
| Type | Fields |
|---|---|
set_title | title |
remove_item | item_id |
set_item_timing | item_id, from_seconds, duration_seconds |
set_item_source | item_id, source_start_seconds, playback_rate |
set_item_audio | item_id, volume_db, audio_fade_in_seconds, audio_fade_out_seconds |
set_audio_levels | item_ids, exclude_item_ids, item_types, audio_roles, volume_db, audio_fade_in_seconds, audio_fade_out_seconds |
set_item_animation | item_id, enter, exit |
set_item_motion | item_id, motion (type, start_seconds, duration_seconds, direction, intensity, loop) |
apply_item_transition | from_item_id, to_item_id, overlap_seconds, enter, exit |
split_item | item_id, at_seconds |
set_item_transform | item_id, left, top, width, height, opacity |
move_item_to_track | item_id, track_id |
set_item_layer_order | item_id, position |
add_solid | from_seconds, duration_seconds, left, top, width, height, style |
add_text | text, from_seconds, duration_seconds, style |
update_text | item_id, text, style |
add_captions | captions, from_seconds, duration_seconds, style |
add_sound_effect | sound_effect_id, url, media_id, from_seconds, duration_seconds, volume_db |
add_voiceover | text, voice_id, from_seconds, volume_db, voice_settings |
update_captions | item_id, captions, style |
generate_captions_from_items | source_item_ids, captions_item_id, language, style |
Caption entries use Remotion-style JSON timing: text, startMs, endMs, optional timestampMs, optional confidence, and optional word-level words.
When track_id is omitted, added media is packed onto compatible existing tracks when timelines do not overlap. Only force a new or explicit track when layer order or overlap requires it.
Music, voiceovers, voice assets, and SFX are audio timeline items. Use set_item_audio for one item, or set_audio_levels to lower/duck groups by audio_roles (sound_effect, music, voiceover, voice, source_video, audio) or by item_types. Older audio items without audioRole are inferred from asset metadata and normalized when matched. Do not remove SFX just to lower their volume.
Use add_voiceover to generate a fresh TTS voiceover from text and add it as an audio item on the timeline. This is a paid operation, so pass a new idempotency_key (or Idempotency-Key header) for each new voice request and reuse it only when retrying the same request. A paid voice request must contain exactly one add_voiceover operation and no other edits; submit additional voiceovers or timeline edits separately. Voiceover text is limited to 465 spoken words. Use set_item_audio on video/audio items to mute, lower, duck, or fade original audio around the voiceover. Use add_editor_media for background music from My Media or an HTTPS URL with audio_role: "music", then lower it with set_item_audio or set_audio_levels.
Use set_item_layer_order with position: "front" for captions and text overlays that must appear above video. New add_text, add_captions, and generated caption items are placed on a front layer by default. When top is omitted, new text overlays choose a safe vertical slot to avoid overlapping existing timed text/captions.
Use add_solid to build editable backgrounds, panels, dividers, chart bars,
route segments, markers, and diagram shapes. Its style accepts color,
border_radius, rotation, and opacity.
Use set_item_animation for native editor visual transitions on videos, images, GIFs, text, and captions. Supported transition types are fade, slide, scale, bounce, flip, zoom, glitch, swipe, float, and snap. Set enter for how an item appears and exit for how it leaves. Pass null for enter or exit to clear an existing transition. Use apply_item_transition when you want a crossfade-style edit: it moves the incoming item earlier so it overlaps the outgoing item, then applies enter/exit animations. Use add_sound_effect for audible transition hits.
Use generate_captions_from_items to create native editor captions from the actual audio in selected video or audio items. It respects each item's timeline placement, source trim, playback rate, and duration, then creates or replaces a front-layer captions item. This requires transcribable remote media on the source items and the configured transcription provider.