curl --request POST \
--url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/ops \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 5e9a2c71-0b4d-4f88-b6a3-7c1d9e0f2a34' \
--data '{
"expected_updated_at": "2026-10-02T12:00:00.000Z",
"note": "Kept only the pricing part",
"ops": [
{
"type": "set_sequence",
"segments": [
{ "asset_id": "asset_1", "source_start_ms": 1200, "source_end_ms": 9800 },
{ "asset_id": "asset_1", "source_start_ms": 14500, "source_end_ms": 31000 }
]
}
]
}'
curl --request POST \
--url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/ops \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 9a1c3e55-7d20-4b18-8e6f-0c4b2a9d7f10' \
--data '{
"ops": [{ "type": "delete_range", "start_ms": 4200, "end_ms": 5600 }]
}'
{
"ok": true,
"code": 200,
"message": "Editor ops applied",
"data": {
"project_id": "b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f",
"title": "Launch cut",
"aspect_ratio": "9:16",
"duration_ms": 25100,
"updated_at": "2026-10-02T12:03:00.000Z",
"assets": [],
"clips": [],
"text_clips": [],
"undo": null,
"render": null,
"editor_url": "https://www.genviral.io/editor/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f?workspace=personal"
}
}
Video Editor
Apply Editor Ops
Cut, rename or style text in a video project with an atomic batch of edit operations.
POST
/
api
/
partner
/
v1
/
editor
/
projects
/
{projectId}
/
ops
curl --request POST \
--url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/ops \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 5e9a2c71-0b4d-4f88-b6a3-7c1d9e0f2a34' \
--data '{
"expected_updated_at": "2026-10-02T12:00:00.000Z",
"note": "Kept only the pricing part",
"ops": [
{
"type": "set_sequence",
"segments": [
{ "asset_id": "asset_1", "source_start_ms": 1200, "source_end_ms": 9800 },
{ "asset_id": "asset_1", "source_start_ms": 14500, "source_end_ms": 31000 }
]
}
]
}'
curl --request POST \
--url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/ops \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 9a1c3e55-7d20-4b18-8e6f-0c4b2a9d7f10' \
--data '{
"ops": [{ "type": "delete_range", "start_ms": 4200, "end_ms": 5600 }]
}'
{
"ok": true,
"code": 200,
"message": "Editor ops applied",
"data": {
"project_id": "b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f",
"title": "Launch cut",
"aspect_ratio": "9:16",
"duration_ms": 25100,
"updated_at": "2026-10-02T12:03:00.000Z",
"assets": [],
"clips": [],
"text_clips": [],
"undo": null,
"render": null,
"editor_url": "https://www.genviral.io/editor/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f?workspace=personal"
}
}
Applies a batch of cutting, rename and text operations to a project and returns the updated project. The batch is
atomic: either every op applies or none does, so a refused batch leaves the project untouched.
A batch holds 1 to 50 ops, applied in order, each against the result of the one before it.
Operations
Ops are objects with a snake_casetype.
type | Fields | Time units | Use it to |
|---|---|---|---|
set_sequence | segments[]: asset_id, source_start_ms, source_end_ms, optional clip_id | Source ms | Replace the base video lane with these source ranges played back to back. Best for “keep only these parts”. |
delete_range | start_ms, end_ms | Timeline ms | Remove a range across all clips and close the gap. Best for dead air. |
split_clip | clip_id, at_ms | Timeline ms | Split a clip in two. |
trim_clip | clip_id, edge (start or end), position_ms | Timeline ms | Move one edge of a clip, trimming its source. |
reorder_clip | clip_id, start_ms | Timeline ms | Move a clip to start at a new position. |
set_title | title (1 to 200 characters) | n/a | Rename the project. The timeline does not change. |
add_text | clip_id, text, start_ms, end_ms, placement and style fields | Timeline ms | Add a text overlay. |
update_text | clip_id, patch with changed text, timing, placement or style fields | Timeline ms | Edit an overlay or caption. |
remove_text | clip_id | n/a | Remove an overlay or caption. |
style_captions | patch with style fields | n/a | Apply one style to all caption clips. |
undo_edit | edit_id (UUID from the project’s undo field) | n/a | Restore the complete state before the latest edit. Send this as the only op. |
set_sequence takes at most 200 segments. Get source ranges for speech from
Get Editor Transcript; get clip ids and timeline positions
from Get Editor Project.
add_text requires percentage placement (x, y, width, height) and
font_family, font_size, color, stroke_color, stroke_width,
background_color (nullable), preset, align and text_case.
lane and font_weight are optional. update_text.patch accepts any subset
of those fields plus text and timing; style_captions.patch accepts style fields.
Read the current clip to preserve its existing placement and appearance.
undo_edit requires expected_updated_at. Use the latest undo.edit_id returned for
your credential. Undo restores all affected clips, captions, overlays, audio and playback
settings. A newer edit in another surface makes the earlier edit unavailable for Undo;
read the project again instead of rebuilding the old cut from source ranges.
Concurrency
Passexpected_updated_at with the updated_at you last read. If the project changed since, the
batch is refused with 409 editor_conflict: read the project again, rebuild your ops against the
new state, and retry with a new Idempotency-Key.
While Vira (the Genviral assistant) is editing the same project, edits are refused with
409 editor_locked. Wait a few seconds and retry.
Idempotency
Idempotency-Key is required and is scoped to the API key (or MCP grant) that sends it.
- Retrying with the same key and the same body returns the original result and never applies the batch twice.
- Reusing a key with a different body returns
409 idempotency_key_reused. - A refused batch (for example
422 clip_not_found) does not consume its key.
Path Parameters
string (UUID)
required
The project id.
Body Parameters
object[]
required
1 to 50 operations, applied in order and atomically.
string
The
updated_at you last read (ISO 8601). The batch is refused with editor_conflict if the
project changed since. Required for undo_edit.string
One short plain-text line (at most 140 characters, no line breaks) describing this step in the
user’s terms, for example
Removed the 20 s where the phone tipped over. The open Genviral web
editor shows it live in its activity feed, labelled with who made the edit (Claude, ChatGPT,
another MCP client, or the API).Response
Returns200 with the updated project, in the same shape as
Get Editor Project. Any earlier render is no longer current
for the new cut. The edit shows live in the Genviral web editor at the project’s editor_url.
curl --request POST \
--url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/ops \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 5e9a2c71-0b4d-4f88-b6a3-7c1d9e0f2a34' \
--data '{
"expected_updated_at": "2026-10-02T12:00:00.000Z",
"note": "Kept only the pricing part",
"ops": [
{
"type": "set_sequence",
"segments": [
{ "asset_id": "asset_1", "source_start_ms": 1200, "source_end_ms": 9800 },
{ "asset_id": "asset_1", "source_start_ms": 14500, "source_end_ms": 31000 }
]
}
]
}'
curl --request POST \
--url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/ops \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 9a1c3e55-7d20-4b18-8e6f-0c4b2a9d7f10' \
--data '{
"ops": [{ "type": "delete_range", "start_ms": 4200, "end_ms": 5600 }]
}'
{
"ok": true,
"code": 200,
"message": "Editor ops applied",
"data": {
"project_id": "b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f",
"title": "Launch cut",
"aspect_ratio": "9:16",
"duration_ms": 25100,
"updated_at": "2026-10-02T12:03:00.000Z",
"assets": [],
"clips": [],
"text_clips": [],
"undo": null,
"render": null,
"editor_url": "https://www.genviral.io/editor/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f?workspace=personal"
}
}
Error Responses
400 invalid_json- request body is not valid JSON400 invalid_request-Idempotency-Keyheader is missing or longer than 255 characters401- authentication failed (missing/invalid/revoked token)404 project_not_found- the project does not exist in the key scope409 editor_locked- Vira is editing this project right now; retry shortly409 editor_conflict- the project changed sinceexpected_updated_at; read it again409 idempotency_key_reused- thisIdempotency-Keywas already used with a different body409 request_in_progress- an identical request with this key is still being processed; retry shortly422 invalid_payload- body failed validation (seeissues)422 invalid_op- an op is not valid for the project; the message says how to correct it422 clip_not_found- an op names aclip_idthat is not in the project422 asset_not_found- an op names anasset_idthat is not in the project422 out_of_range- a time or range falls outside the clip, asset, or timeline422 invalid_document- the resulting cut would not be a valid project
