Skip to main content

What is a cut

A cut is the decision of which spans of the source to keep. It’s a list of {start, end} segments on the source timeline, stored as its own entity and bound to an asset (1:N — an asset can have many cuts). You drive the editor from it: export the cut to your NLE, or feed it to a render to get a flattened video or audio output. Roughy computes the cut from your asset — plus an optional reference script (the intended final message) you pass on the request — dropping filler, restarts, and off-topic spans while preserving pacing.

Triggering a cut

curl https://api.roughy.ai/v1/cuts \
  -H "Authorization: Bearer $ROUGHY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "asset_id": "<video-or-audio-id>", "script": "optional reference text" }'
asset_id may be a video or an audio asset. The script is an optional field on this request: pass the intended final message and the cut aligns to it, or omit it (null) for a scriptless cut. The response is the cut row, with the request’s script frozen onto it:
{ "id": "<cut_id>", "asset_id": "<asset_id>", "state": "pending", "script": null }
Poll GET /v1/cuts/{cut_id} until state is completed, then export the cut via /v1/cuts/{cut_id}/export. Or skip polling and subscribe to webhooks (cut.completed / cut.failed).

Pre-conditions

A cut can only be produced once the asset is cuttable — fully prepared and paid for. Check the cuttable boolean on the asset (GET /v1/assets/{id}); while it is false, POST /v1/cuts returns 409 with a typed code:
codeMeaning
asset_processingThe asset is still being prepared. Transient — back off for the Retry-After seconds and retry.
asset_payment_requiredThe asset is prepared but unpaid (pending_payment). Top up, then retry.
asset_failedThe asset failed preparation and can’t be cut. Re-upload.

Idempotency

POST /v1/cuts is idempotent on (asset, script):
  • The first request for a given (asset, script) creates a new cut and returns it (201, with a Location header).
  • A repeat request with the same (asset, script) returns the existing cut (200) — no second cut, no second charge. The same request body always gives you the same cut.
  • A request with a different script (on the same asset) is a new cut (201). Cuts are 1:N per asset, so distinct scripts coexist.
A scriptless request (script omitted / null) dedups the same way — two full-auto cuts on one asset return the same cut. The script you pass is snapshotted onto the cut, so a cut is a permanent record of one cutting attempt:
  • Another take? Post with a different script — you get a new cut_id; earlier cuts stay until you remove them.
  • Clean up with DELETE /v1/cuts/{cut_id} — this also removes that cut’s subtitle and any renders derived from it, and cancels any in-flight renders of it.
A completed cut is immutable. A failed cut is not reused — a fresh request starts a new attempt; delete the failed one when you no longer need it.

Subtitles

When a cut completes, Roughy generates a subtitle for it — word-level caption lines remapped onto the cut’s output timeline, bound 1:1 to the cut. Export it straight off the cut — it’s addressed via its parent cut_id:
curl "https://api.roughy.ai/v1/cuts/{cut_id}/subtitle/export?format=vtt" \
  -H "Authorization: Bearer $ROUGHY_API_KEY"
FormatNotes
srtSubRip, line-level timing.
vttWebVTT with inline per-word karaoke timestamps.

Exporting a cut

Stream the cut as an edit-decision file for your NLE — synchronous, free, no render required:
curl "https://api.roughy.ai/v1/cuts/{cut_id}/export?format=xmeml" \
  -H "Authorization: Bearer $ROUGHY_API_KEY"
FormatTarget
xmemlPremiere Pro / DaVinci Resolve (FCP7 XML).
fcpxmlFinal Cut Pro X.
edlCMX-3600 EDL — broadly accepted.
otioOpenTimelineIO JSON.
  • Render — flatten a cut into a video or audio output.
  • Asset — what a cut is bound to.
  • Credit ledger — cuts are free; you pay once per source asset.