ScramboREST API

REST API reference

Upload footage, request an edit, and deliver a browser view or render handoff.

Scrambo turns uploaded footage into a revisioned edit. Your integration only needs to manage a session, a few returned IDs, and the output your product needs.

Before you start

SettingValue
Base URLhttps://api.scrambo.dev
AuthenticationAuthorization: Bearer <token> · Request API access
JSON requestsContent-Type: application/json

V2 does not use the X-Scrambo-SDK-Version header.

Each authenticated identity can have one active project. Creating a session closes that identity's previous active session. Give independently operating users or integrations distinct credential identities.

Request lifecycle

One session. IDs connect each request to the next.

  1. 01

    Start

    Open a workspace for one video.

    1. 1Create session
      POST/v2/sessions

      Keep sessionId

  2. 02

    Add media

    Register the file, then send its bytes.

    1. 2Declare asset
      POST/v2/sessions/{sessionId}/assets

      Keep assetId, SHA-256, size

    2. 3Upload bytes
      PUT/v2/sessions/{sessionId}/assets/{assetId}/content

      Keep upload receipt

  3. 03

    Make the edit

    Submit direction and follow the work.

    1. 4Submit turn
      POST/v2/sessions/{sessionId}/turns

      Keep requestId, operationId

    2. 5Poll progress
      GET/v2/operations/{operationId}?after={cursor}

      Keep status, latest cursor

  4. 04

    Deliver

    Choose a browser view or render handoff.

    1. 6Create snapshot
      POST/v2/sessions/{sessionId}/view-edit-snapshots

      Keep URL, operation, expiry

    2. 7Create handoff
      POST/v2/sessions/{sessionId}/render-handoffs

      Keep operationId

    3. 8Download handoff
      GET/v2/sessions/{sessionId}/render-handoffs/{handoffId}

      Keep manifest

    4. 9Close session
      POST/v2/sessions/{sessionId}/close

      Keep terminal state

The first five steps get you to a working edit. From there, create a browser snapshot for review, or create and download a render handoff for your own renderer. Close the session when the user is done.

Your first edit

1. Create a session and upload media

Create the session and keep its sessionId. For every file, declare its name, byte size, MIME type, and SHA-256 digest; keep the returned assetId, then upload the exact bytes.

ExampleSet up curl, create a session, and upload a file
export SCRAMBO_API_URL="https://api.scrambo.dev"
export SCRAMBO_API_TOKEN="replace-with-your-token"
export VIDEO="./interview.mp4"

api() {
  curl --fail-with-body --silent --show-error \
    -H "Authorization: Bearer $SCRAMBO_API_TOKEN" \
    -H "Content-Type: application/json" \
    "$@"
}

SESSION_ID=$(api -X POST "$SCRAMBO_API_URL/v2/sessions" \
  --data '{"project":"first-edit","canvas":[1080,1920]}' \
  | jq -r '.sessionId')

VIDEO_SIZE=$(wc -c < "$VIDEO" | tr -d ' ')
VIDEO_SHA256=$(openssl dgst -sha256 -r "$VIDEO" | awk '{print $1}')

ASSET_ID=$(api -X POST \
  "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/assets" \
  --data "$(jq -n \
    --arg name "$(basename "$VIDEO")" \
    --argjson size "$VIDEO_SIZE" \
    --arg sha256 "$VIDEO_SHA256" \
    '{name:$name,size:$size,mimeType:"video/mp4",sha256:$sha256}')" \
  | jq -r '.assetId')

curl --fail-with-body --silent --show-error \
  -X PUT "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/assets/$ASSET_ID/content" \
  -H "Authorization: Bearer $SCRAMBO_API_TOKEN" \
  -H "Content-Type: video/mp4" \
  --data-binary "@$VIDEO"

2. Submit editing turns

Every instruction goes to the same /turns endpoint. A dependable first edit uses three turns in order:

GoalAgentWhat to send
Understand the footagesource.workWhat to find or transcribe
Plan the storyplanner.compileThe desired length, structure, and emphasis
Build the edittimeline.authorOmit message to build the current plan

Wait for each turn to succeed before submitting the next. Keep the returned operationId; a successful Author result also gives you the current editId.

ExampleSubmit the three-turn editing sequence
# 1. Understand the footage.
OPERATION_ID=$(api -X POST "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/turns" \
  --data '{
    "requestId":"source-1",
    "mode":"edit",
    "agent":"source.work",
    "message":"Transcribe the dialogue and identify the strongest moments.",
    "tools":["transcribe"]
  }' | jq -r '.operationId')

# After source.work succeeds, submit planner.compile and keep its operation.
OPERATION_ID=$(api -X POST "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/turns" \
  --data '{
    "requestId":"plan-1",
    "mode":"edit",
    "agent":"planner.compile",
    "message":"Plan an energetic 30-second story. Open with the strongest hook."
  }' | jq -r '.operationId')

# After planner.compile succeeds, build its plan and keep the operation.
OPERATION_ID=$(api -X POST "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/turns" \
  --data '{
    "requestId":"author-1",
    "mode":"edit",
    "agent":"timeline.author"
  }' | jq -r '.operationId')

3. Poll the operation

Poll with the latest cursor until status is succeeded, failed, or cancelled. Send the returned cursor as the next after value so you only receive new progress events.

ExamplePoll for progress
api "$SCRAMBO_API_URL/v2/operations/$OPERATION_ID?after=0" | jq

4. Deliver the result

Create a snapshot when a user needs a browser review. Create a render handoff when another renderer needs the edit and verified asset manifest.

ExampleCreate a browser snapshot, then close the session
api -X POST \
  "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/view-edit-snapshots" \
  --data '{}'

# Open the returned viewUrl. Close only after the user is finished.
api -X POST "$SCRAMBO_API_URL/v2/sessions/$SESSION_ID/close" \
  --data '{}'

Concepts in plain English

ResourceThink of it asKeep
SessionOne user's video workspacesessionId, currentEditId
AssetOne verified media fileassetId, SHA-256, byte size
TurnOne question or editing instructionYour unique requestId
OperationThe work running in the backgroundoperationId, latest cursor
SnapshotA temporary browser view of one editviewUrl, expiry
Render handoffThe edit and asset manifest for a rendererhandoffId

Endpoint reference

MethodPathPurpose
POST/v2/sessionsCreate an empty stateful editing session.
GET/v2/sessions/{sessionId}Read session state, assets, and currentEditId.
POST/v2/sessions/{sessionId}/assetsDeclare an asset's name, size, MIME type, and SHA-256 digest.
PUT/v2/sessions/{sessionId}/assets/{assetId}/contentUpload the declared asset as raw bytes.
POST/v2/sessions/{sessionId}/turnsSubmit an idempotent ask or edit turn.
GET/v2/operations/{operationId}?after={cursor}Poll status and receive events newer than cursor.
POST/v2/sessions/{sessionId}/view-edit-snapshotsCreate a detached browser view of an edit.
POST/v2/sessions/{sessionId}/render-handoffsStart a renderer-neutral handoff for an edit.
GET/v2/sessions/{sessionId}/render-handoffs/{handoffId}Download an authenticated handoff manifest.
POST/v2/sessions/{sessionId}/closeCancel active work and close the private session.

JSON request objects are closed: unknown fields are rejected.

Sessions and assets

POST /v2/sessions accepts:

FieldRequiredMeaning
projectYesProject name, 1–120 characters.
canvasNo[width, height]; each value must be a positive integer no larger than 16384.
providerNoObject with name and optional model and thinking; omit it to use service defaults.

To upload a file, first declare it with name, size, sha256, and optional mimeType. Then PUT the raw bytes to the returned asset URL. An asset is only available to agents after its byte count and digest have been verified.

Turns

All agent work uses POST /v2/sessions/{sessionId}/turns. There are two request modes.

An ask turn performs read-only analysis and returns text:

{
  "requestId": "ask-1",
  "mode": "ask",
  "message": "Which moments best support a 30-second customer story?"
}

An edit turn runs one allowlisted specialist:

{
  "requestId": "captions-1",
  "mode": "edit",
  "agent": "timeline.captions",
  "baseEditId": "latest-edit-id",
  "message": "Add bold, readable captions timed to the dialogue."
}
AgentWhat it doesMessage and revision rules
source.workUnderstands uploaded media and publishes the current source brief.Requires message; never accepts baseEditId.
source.generateGenerates media and publishes a source brief over the results.Requires message and at least one of img2video or voiceover; never accepts baseEditId.
planner.compileTurns the current source brief into a grounded plan.Requires message; never accepts baseEditId.
timeline.authorCreates the structural edit.Omit message and baseEditId to build the current plan as a new root; use message for direct authoring.
timeline.graphicsAdds shapes, panels, backings, and accents.Requires message and the latest baseEditId.
timeline.soundAdds music, sound effects, balance, and ducking.Requires message and the latest baseEditId.
timeline.titlesAdds titles, cards, lower thirds, and typography.Requires message and the latest baseEditId.
timeline.captionsAdds transcript-aligned captions.Requires message and the latest baseEditId.

Common edit-turn fields:

FieldMeaning
requestIdRequired idempotency key, 1–200 characters, scoped to the session.
modeedit.
agentOne agent ID from the table above.
messageNatural-language instruction, up to 20,000 characters. Only plan-backed Author may omit it.
baseEditIdRevision the timeline specialist must extend. See Revision rules.
toolsUp to four explicitly granted capabilities. Grants apply only to this turn.
toolConfigPer-tool configuration. Every configured tool must also appear in tools.

source.generate additionally accepts budgetUsd (default 5.0), maxCalls (default 4), and name (1–80 characters). The deployment's default ceilings are $15 and 15 requested outputs; requests over the active ceiling fail with generation_limit_exceeded.

For example:

{
  "requestId": "generate-tour-1",
  "mode": "edit",
  "agent": "source.generate",
  "message": "Create a narrated 16:9 property tour from the uploaded photos.",
  "tools": ["img2video", "voiceover"],
  "toolConfig": {
    "img2video": {
      "resolution": "720p",
      "duration": 6,
      "aspectRatio": "16:9"
    }
  },
  "budgetUsd": 5,
  "maxCalls": 10,
  "name": "listing-tour-assets"
}

Tool grants

Tools are opt-in capabilities, not separate HTTP endpoints. The specialist decides whether and how to use the capabilities granted for that turn.

ToolAllowed agentsConfiguration
transcribesource.work, planner.compile, timeline.authorprovider, model, language, diarize; word timestamps are always enabled.
detect_eventssource.work, planner.compile, timeline.authorsampleDensity: sparse or dense; maxFrames: 1–2400.
detect_beatssource.workNo configuration.
maskingEvery edit agentNo caller configuration.
img2videosource.generateGeneration settings such as vendor, resolution, duration, and aspectRatio.
voiceoversource.generateGeneration settings such as vendor and voice.

Operations and results

Turns, browser snapshots, and render handoffs are asynchronous. A submission returns 202 with an operationId and its current status (normally queued or running; an idempotent replay can already be terminal). Poll:

GET /v2/operations/{operationId}?after=0

The response contains:

FieldMeaning
statusqueued, running, succeeded, failed, or cancelled.
cursorLatest event cursor. Send it as the next after value.
eventsProgress events newer than after.
resultPresent after success. Its type selects the result shape.
errorPresent after failure or cancellation.
Result typeImportant fields
answeranswer
sourceagent, artifact, editId
planagent, artifact, editId
editagent, editId, previousEditId, artifact
view_edit_snapshoteditId
render_handoffhandoffId, editId

Artifacts include name, kind, executionId, fingerprint, result, llmInvoked, and cached.

Every error has a stable code, a safe message, and retryable. Use retryable rather than guessing from the message. Synchronous HTTP errors use the same envelope:

{
  "error": {
    "code": "edit_conflict",
    "message": "baseEditId is stale",
    "retryable": false
  }
}

Idempotency and revision rules

requestId is an idempotency key scoped to one session. Replaying the same ID with the same canonical body returns the original operation. Reusing it for a different body returns 409 idempotency_conflict.

Timeline revisions form one linear chain:

  • A direct first timeline.author turn omits baseEditId.
  • Plan-backed timeline.author omits both message and baseEditId; it creates a new root revision from the current plan.
  • Every later timeline turn sends the latest successful editId as baseEditId.
  • A stale or missing base revision returns 409 edit_conflict.
  • source.work, source.generate, and planner.compile never accept baseEditId and do not advance the edit chain.

Read currentEditId from GET /v2/sessions/{sessionId} when recovering local client state.

Browser snapshots and render handoffs

A browser snapshot is a detached view of one revision. Pass an optional editId; omitting it selects the current revision. Snapshot creation returns a viewUrl immediately. Open it before waiting for the operation because the browser connection completes hydration. Later agent turns do not change the snapshot, and manual changes in that browser are not durable API revisions.

A render handoff is an authenticated, renderer-neutral manifest for a selected revision:

{
  "requestId": "render-handoff-1",
  "editId": "edit-id-to-render"
}

Submit it to /v2/sessions/{sessionId}/render-handoffs, poll the returned operation, then download /v2/sessions/{sessionId}/render-handoffs/{handoffId}. Uploaded media is identified by asset ID, SHA-256 digest, byte size, and MIME type so an external renderer can resolve and verify its local copy.

On this page