API reference

CaptureBeam API

POST a YAML, poll the job, get an MP4. Bearer-authed, JSON in / JSON out.

Base URL

https://capturebeam.com/api/v1

Authentication

Every request needs an API key. Create one in your dashboard; the key is shown once and stored hashed. Send it as a Bearer token:

Authorization: Bearer cb_live_xxxxxxxxxxxxx

x-api-key: cb_live_… is also accepted for clients that don't play nicely with Authorization.

Endpoints

POST/v1/renders

Submit a demo for rendering. Returns immediately with a job ID and a link to edit the demo in the dashboard.

Three body shapes are accepted:

  • application/json{ "yaml": "title: ...", "name"?: "..." }
  • application/json{ "projectId": "pj_..." }
  • text/yaml — raw YAML body

Raw-YAML submissions auto-create a Project so the user can tweak the demo and re-render from the dashboard. The response includes editUrl pointing at that project.

Example

curl -X POST https://capturebeam.com/api/v1/renders \
  -H "Authorization: Bearer cb_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"projectId": "pj_a1b2c3d4"}'

# 202 Accepted
{
  "id": "rj_a1b2c3d4e5f6",
  "status": "pending",
  "projectId": "pj_a1b2c3d4",
  "editUrl": "https://capturebeam.com/dashboard/projects/pj_a1b2c3d4",
  "statusUrl": "https://capturebeam.com/api/v1/renders/rj_a1b2c3d4e5f6",
  "docsVersion": "3.5.0",
  "meta": { "version": 1 }
}
GET/v1/renders/{id}

Poll a job's status. Poll every 2-3 seconds; jobs typically take 20-40 seconds.

Example

curl https://capturebeam.com/api/v1/renders/rj_a1b2c3d4e5f6 \
  -H "Authorization: Bearer cb_live_xxxxxxxxxxxxx"

# 200 OK — running, with live progress
{
  "id": "rj_…",
  "status": "running",
  "videoUrl": null,
  "manifestUrl": null,
  "steps": null,
  "error": null,
  "durationMs": null,
  "createdAt": "2026-01-15T12:00:00Z",
  "projectId": "pj_…",
  "editUrl": "https://capturebeam.com/dashboard/projects/pj_…",
  "progress": { "current": 3, "total": 8, "stepType": "click" },
  "docsVersion": "3.5.0",
  "meta": { "version": 1 }
}

# 200 OK — succeeded
{
  "id": "rj_…",
  "status": "succeeded",
  "videoUrl": "https://media.capturebeam.com/render-….mp4",
  "manifestUrl": "https://media.capturebeam.com/manifest-….json",
  "durationMs": 22400,
  "steps": [
    { "index": 0, "type": "goto", "status": "ok", "durationMs": 1240 },
    { "index": 1, "type": "click", "status": "ok",
      "resolvedSelector": "getByRole(button, name=\"Sign in\")",
      "durationMs": 380 }
  ],
  "createdAt": "2026-01-15T12:00:00Z",
  "projectId": "pj_…",
  "editUrl": "https://capturebeam.com/dashboard/projects/pj_…",
  "progress": null,
  "docsVersion": "3.5.0",
  "meta": { "version": 1 }
}

# 200 OK — succeeded with one step skipped
{
  "id": "rj_…", "status": "succeeded",
  "videoUrl": "https://…",
  "steps": [
    { "index": 0, "type": "goto", "status": "ok" },
    { "index": 1, "type": "click", "status": "failed",
      "error": "Could not resolve target { role: \"button\", name: \"Buy\" } …" }
  ]
}

# 200 OK — failed
{
  "id": "rj_…",
  "status": "failed",
  "error": "Render timed out after 600000ms (last phase: remotion-render)…",
  "steps": null
}

videoUrl and manifestUrl are signed URLs valid for 24 hours. steps is the compact per-step summary — index, type, status (ok/skipped/failed), optional error, optional resolved selector. progress is non-null while status === "running" so dashboards can show “Step 3 of 8 · click”.

POST/v1/renders/{id}/share

Create a stable public or password-protected watch link for a finished render.

The render must belong to the API key's user and have succeeded. Password-protected shares require a password; the password protects the watch page and MP4 download. Agent read/clone endpoints do not expose password-protected shares.

Example

curl -X POST https://capturebeam.com/api/v1/renders/rj_a1b2c3d4e5f6/share \
  -H "Authorization: Bearer cb_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"permission":"public","cloneable":true}'

# 201 Created
{
  "id": "sr_a1b2c3d4e5f6",
  "shortCode": "abc1234567",
  "url": "https://capturebeam.com/s/abc1234567",
  "shareUrl": "https://capturebeam.com/s/abc1234567",
  "permission": "public",
  "expiresAt": null,
  "cloneable": true,
  "createdAt": "2026-05-27T12:00:00.000Z",
  "docsVersion": "3.5.0",
  "meta": { "version": 1 }
}

For a password-protected link, send { "permission": "password", "password": "..." } and share the password separately from the URL.

POST/v1/probe

Scan a URL for interactive elements. Use to author valid targets before submitting a render.

Returns the page's buttons, links, inputs, and ARIA-tagged elements with their accessible names — exactly the shapes you can use as target values. The endpoint path stays /v1/probe for backward compatibility with existing keys.

curl -X POST https://capturebeam.com/api/v1/probe \
  -H "Authorization: Bearer cb_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://app.example.com"}'

# 200 OK
{
  "url": "https://app.example.com",
  "status": 200,
  "title": "Example",
  "elements": [
    { "role": "button", "name": "Sign in",
      "target": { "role": "button", "name": "Sign in" } },
    { "role": "textbox", "name": "Email",
      "target": { "role": "textbox", "name": "Email" } }
  ],
  "truncated": false
}
GET/v1/schema

JSON Schema for demo.yaml plus a quick-reference summary. Use to validate client-side or to pin against the live contract.

Public — no auth required. Includes docsVersion and a changelog so cached agent skills can detect when the contract has changed.

Status codes

CodeMeaning
202Render queued. Poll the job ID.
201Share link created.
200Job state retrieved.
400Missing or malformed body. Check yaml / projectId.
401Missing or invalid API key.
402No active subscription. Upgrade.
404Project not found, or doesn't belong to your account.
409Render is not shareable yet; wait for succeeded.
429Concurrency limit reached.
500Server error. Retry safe — the job stays in pending.

Render-and-wait

Most CI integrations want a single blocking call. This shell pattern submits and polls until done:

#!/usr/bin/env bash
set -euo pipefail
KEY=${CAPTUREBEAM_KEY:?}
BASE=https://capturebeam.com

JOB_ID=$(curl -sS -X POST $BASE/api/v1/renders \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"pj_a1b2c3d4"}' | jq -r .id)

while :; do
  RES=$(curl -sS $BASE/api/v1/renders/$JOB_ID \
    -H "Authorization: Bearer $KEY")
  STATUS=$(echo "$RES" | jq -r .status)
  case "$STATUS" in
    succeeded) echo "$RES" | jq -r .videoUrl; exit 0 ;;
    failed)    echo "$RES" | jq -r .error >&2; exit 1 ;;
    *)         sleep 3 ;;
  esac
done

Limits

  • Concurrency: 3 simultaneous renders per account. The 4th returns 429 — back off and retry.
  • Polling: no rate limit on the status endpoint. Two- to three-second intervals are typical.

Versioning

Every API response includes a docsVersion field (semver). Compare against the version your client was written against. PATCH bumps are clarifications; MINOR adds new optional fields; MAJOR may change semantics. Read the changelog on GET /v1/schema to see what changed.