Skip to content

The analysis lifecycle

A session moves through four states:

stateDiagram-v2
    [*] --> pending: POST /api/sessions/<br/>debits 1 session
    pending --> processing: a worker picks it up
    processing --> completed: analysis finished
    processing --> failed: analysis failed
    failed --> pending: reanalyze<br/>re-takes a slot
    completed --> pending: reanalyze<br/>free, still holds its debit
    note right of failed
        quota refunded automatically
    end note
status Meaning
pending Queued. No worker has picked it up.
processing Running. progress carries the current stage.
completed Done. metrics, metric_targets, analyzed_url are populated.
failed failure_reason says why — and the quota slot is refunded automatically.

There are no webhooks yet. Poll GET /api/sessions/{id}/.

A typical clip finishes in tens of seconds. The first request after a quiet period may take ~10 s longer because the GPU scales to zero between bursts — that is a cold start, not a stall.

While processing, the progress object carries the worker’s most recent stage:

{
"stage": "pose_extract",
"stage_idx": 2,
"frame_done": 431,
"frame_total": 900
}

A failed session returns its quota slot automatically. Deleting the failed row afterwards refunds nothing extra — a debit is refunded at most once.

Re-running an existing session with POST /api/sessions/{id}/reanalyze/ is free if the session still holds its original debit. One that already failed released its slot, so the re-run re-takes it, and can return 402 quota_exhausted if the slot was spent elsewhere in between.

A team can choose to delete the unblurred original of a face-blurred session a day after its analysis. Such a session reads source_deleted: true with an empty video_url; analyzed_url, anonymized_url and the metrics stay, and a re-run answers 409 source_deleted. Keep what you need from the session when it completes rather than counting on a later re-run.

This is the part most integrations miss.

capture_findings is a list of quality problems detected in the footage, and it appears on completed sessions — not failed ones. The analysis ran and a report exists, but its numbers need care:

{ "code": "pose_sparse", "severity": "advisory", "data": { "detection_ratio": 0.42 } }

Every finding carries a severity:

  • advisory — the angles, phases and scores in that report were computed from footage the tracker could not read properly. Five codes: pose_sparse, implausible_geometry, subject_too_far, camera_off_plane, subject_left_frame.
  • note — the report is fine to read, with one caveat. frame_rate_low means a movement we analyse at 60 fps was filmed at 24–30 fps, so its fastest moments (contacts, take-offs, peak speeds) are timed less precisely.

Surface them. A report with pose_sparse should reach the coach as “re-film this”, not as a result — and it did consume a session, because it processed to a finished report. A note belongs beside the numbers it qualifies, not in place of them. The troubleshooting guide covers what each code means and how to fix the recording.