Skip to main content

Errors worth branching on

These five failures cover the replay fetch (GET /api/v1/sessionreplay/), every screen-recording view from the dashboard. Each block below is a full { error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the error handling guide.

401 — Unauthorized

A 401 on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.

403 — Forbidden

A 403 means the key authenticated but the operation is gated by scope — check the key’s scopes on the developer page; a 403 is never a data-not-found shape.

422 — Schema

A 422 means the payload did not match the request schema — branch on error.details.field and resend with the tenant-scoped session id instead of blind-retrying the same body.

429 — Rate

The Retry-After header and error.details.retry_after are both set on every 429 — resend the SAME request after the lower of the two.

404 — Not found

Surface retention info to the operator — a retry cannot restore the asset.

60-second retry matrix

Violations behind the score

Weights used by the ranked list’s counts and the per-session timeline scoring: rage_click 3, error_click 3, dead_click 2, u_turn 2. A click reports at most one violation — a click that precedes a JS error counts as error_click (not dead_click), and a rage burst consumes its member clicks once. This is what makes the score comparable across sessions: it’s a count of distinct problems, not repeated counting of the same click. The daily triage loop that consumes these weights lives in High-friction sessions: read frustration signals.

Worked request and response samples

Copy a request as written, substitute your own ids, and compare the response envelope. Every example uses the same { data, meta } shape as the error sections above.

List recent recordings

GET /api/v1/session-replay
Each row is a lightweight summary. Use recording_id, playback_token, started_at, and duration_ms to identify a replay; when offloaded is true, fetch the conversation to load the complete event stream.

Get a recording for playback

GET /api/v1/session-replay/{conversationId}
The response returns the stored replay event stream, not a raw video URL. The list row’s recording_id identifies the same recording; status, timestamps, and event fields describe its playback data.

Frustration-signal timeline

GET /api/v1/session-replay/frustration/{conversationId}
Signals are ordered by event time. t_ms is relative to the recording start, so a player can place each marker without exposing event payload details.

High-friction ranked list

GET /api/v1/session-replay/frustration/sessions
The list includes only recordings with a score above zero, ordered highest first. Use conversation_id to open the recording and its timeline.