API reference
One REST API over everything the product does: upload a recording, read what the AI concluded, share it, export it, search across it, and receive the reports your own visitors file. JSON in, JSON out, cursor pagination, and RFC 7807 problem responses.
Authentication
Create a key under Dashboard → Developers (Pro and above). Keys are shown once, hashed at rest, scoped to the workspace that created them, and prefixed sr_live_. Send it as a bearer token on every request:
curl https://api.scenerecap.com/v1/recordings \
-H "Authorization: Bearer sr_live_…"Conventions
| Base URL | https://api.scenerecap.com |
| Versioning | Path-prefixed /v1. Additive changes ship without a version bump; removals do not. |
| Pagination | Cursor. Pass limit (1 to 100, default 30) and cursor (the ISO timestamp from nextCursor). A null nextCursor means the last page. |
| Workspace | A key is pinned to the workspace it was created in. Leave out workspace / workspaceId and a request uses that workspace; naming any other workspace returns 404. |
| Rate limit | 300 requests per minute per client IP address, across all endpoints. Over that you get 429; retry after a short backoff. |
| Errors | RFC 7807 application/problem+json with status, title and detail. A 402 means a plan limit, not a payment failure. |
| Timestamps | ISO 8601, UTC. Timeline offsets are seconds from the start of the recording. |
Endpoints
Recordings
/v1/recordings/v1/recordings/:id/v1/recordings/preflight/v1/recordings/v1/recordings/:id/v1/recordings/:id/v1/recordings/:id/reanalyze/v1/recordings/:id/retry/v1/recordings/:id/events/v1/recordings/:id/voiceover/v1/recordings/:id/repro/v1/recordings/:id/perform/v1/recordings/:id/takes/v1/takes/:id/approve/v1/takes/:id/v1/outputs/:idUploads
/v1/uploads/v1/uploads/:id/completeExports and search
/v1/recordings/:id/exports/v1/recordings/:id/exports/v1/recordings/:id/agent-export?kind=skill|agent_md/v1/searchReporting widget and Inbox
/v1/workspaces/:id/site-keys/v1/workspaces/:id/site-keys/v1/site-keys/:id/v1/site-keys/:id/v1/workspaces/:id/reports/v1/reports/:idFiling to your tracker
/v1/integrations/v1/integrations/:provider/resources/v1/integrations/:provider/v1/recordings/:id/create-issue/v1/recordings/:id/notion-export/v1/integrations/:providerWorkspaces, folders and people
/v1/me/v1/workspaces/v1/workspaces/:id/members/v1/workspaces/:id/members/:userId/v1/workspaces/:id/members/:userId/v1/workspaces/:id/invites/v1/workspaces/:id/invites/v1/invites/:id/resend/v1/invites/:id/v1/invites/accept/v1/workspaces/:id/folders/v1/workspaces/:id/folders/v1/folders/:id/v1/folders/:id/v1/workspaces/:id/billing/v1/workspaces/:id/billing/invoicesChecks
/v1/checks/v1/checks/v1/checks/:id/v1/checks/:id/v1/checks/:id/v1/checks/:id/runs/v1/check-runs/:id/v1/check-runs/:id/bug-reportLiving tutorials
/v1/living-tutorials/v1/living-tutorials/v1/recordings/:id/living-tutorial/v1/living-tutorials/:id/v1/living-tutorials/:id/v1/living-tutorials/:id/v1/living-tutorials/:id/refresh-now/v1/living-tutorials/:id/refresh/v1/living-tutorials/:id/rotate-secret/v1/living-tutorials/:id/refreshes/:refreshId/v1/living-tutorials/:id/refreshes/:refreshId/approve/v1/living-tutorials/:id/refreshes/:refreshId/discard/v1/living-tutorials/:id/versions/:versionId/restoreAgent runs
/v1/recordings/v1/recordings/:id/v1/recordings/:id/sign-offSigned-in sessions and verified sites
/v1/verified-origins/v1/verified-origins/:id/verify/v1/verified-origins/v1/verified-origins/:id/v1/run-sessions/v1/run-sessions/v1/run-sessions/:idKeys and webhooks
/v1/workspaces/:id/api-keys/v1/workspaces/:id/api-keys/v1/api-keys/:id/v1/workspaces/:id/webhooks/v1/workspaces/:id/webhooks/v1/webhooks/:id/v1/webhooks/:id/deliveries/v1/webhooks/:idWorked example: upload and analyse
Three calls. Open a session, PUT the parts, then create the recording; the pipeline starts on its own. On a plan with limits, ask first, so a refusal costs one call and not an upload:
# 0. (optional) would the plan accept it? 200, or 402 naming the limit
curl -sX POST https://api.scenerecap.com/v1/recordings/preflight \
-H "Authorization: Bearer $SR_KEY" -H "content-type: application/json" \
-d '{"mode":"bug_report","durationSec":48}'
# 1. open a multipart session
curl -sX POST https://api.scenerecap.com/v1/uploads \
-H "Authorization: Bearer $SR_KEY" -H "content-type: application/json" \
-d '{"kind":"media","filename":"session.webm","contentType":"video/webm","sizeBytes":8123456}'
# -> { "uploadId": "…", "partSize": 8388608, "parts": [{ "n": 1, "url": "https://…" }] }
# 2. PUT each part to its presigned url, keeping the ETag each one returns
curl -sX PUT "$PART_URL" --data-binary @part-1.bin -D - | grep -i etag
# 3. complete, then create the recording
curl -sX POST https://api.scenerecap.com/v1/uploads/$UPLOAD_ID/complete \
-H "Authorization: Bearer $SR_KEY" -H "content-type: application/json" \
-d '{"parts":[{"n":1,"etag":"abc123"}]}'
curl -sX POST https://api.scenerecap.com/v1/recordings \
-H "Authorization: Bearer $SR_KEY" -H "content-type: application/json" \
-d '{"uploadId":"'$UPLOAD_ID'","title":"Checkout fails","mode":"bug_report"}'Poll GET /v1/recordings/:id until status is ready, then read outputs for the bug report, tutorial, explanation or recap.
Worked example: triage the widget Inbox
Duplicates arrive already grouped, so one row can stand for many reports.
curl -s "https://api.scenerecap.com/v1/workspaces/$WS/reports?status=new" \
-H "Authorization: Bearer $SR_KEY"
# -> reports[0].clusterCount === 5 (five visitors, one bug, one row)
# file it, then mark it triaged with the issue you created
curl -sX POST https://api.scenerecap.com/v1/recordings/$REC/create-issue \
-H "Authorization: Bearer $SR_KEY" -H "content-type: application/json" \
-d '{"provider":"linear"}'
curl -sX PATCH https://api.scenerecap.com/v1/reports/$REPORT \
-H "Authorization: Bearer $SR_KEY" -H "content-type: application/json" \
-d '{"status":"triaged","issueUrl":"https://linear.app/…"}'Webhooks
Register a URL under Developers and choose your events: recording.ready, recording.shared, comment.created, check.failed, check.recovered, agent_run.reviewed. Each delivery is a JSON POST carrying X-SceneRecap-Event, X-SceneRecap-Delivery and X-SceneRecap-Signature: sha256=<hex>, an HMAC-SHA256 of the raw body using the secret shown once at creation.
=== instead of a timing-safe compare leaks the secret a byte at a time.import crypto from "node:crypto";
export function verify(rawBody: Buffer, header: string, secret: string): boolean {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(header);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Non-2xx responses are retried with exponential backoff up to three attempts in total (the first delivery plus two retries), and every attempt (status, response body, timing) is visible in the Deliveries panel.
Check alerts fire on a change only: check.failed when a passing check starts failing, and check.recovered when it passes again. A blocked or error run sends neither.
Worked example: refresh a tutorial after a deploy
Call the tutorial’s refresh URL from your deploy pipeline. It takes no API key: sign the request with the tutorial’s own secret, over <timestamp>.<body>, so a captured request cannot be replayed later. Requests more than five minutes old are refused, and every refusal is the same 401.
TS=$(date +%s)
BODY='{"ref":"'$GIT_SHA'"}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$TUTORIAL_SECRET" -hex | sed 's/^.* //')
curl -sX POST https://api.scenerecap.com/v1/living-tutorials/$TUTORIAL/refresh \
-H "content-type: application/json" \
-H "X-SceneRecap-Timestamp: $TS" \
-H "X-SceneRecap-Signature: sha256=$SIG" \
-H "Idempotency-Key: deploy-$GIT_SHA" \
-d "$BODY"
# a retry with the same Idempotency-Key answers 200 with "replayed": true and costs nothingPlan limits
Limits are enforced server-side and return 402 with a message naming the limit. API keys require Pro; the reporting widget is a paid add-on; export formats, AI analyses, agent runs (Repro Agent verdicts and Takes draw from one pool), check runs, tutorial refreshes each have their own monthly allowance. See pricing for the current numbers.