Describe a just-uploaded clip, before it becomes a session
const url = 'http://localhost:8000/api/sessions/probe/';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"session_id":"3c613c61-ec7f-42bd-9de3-6577b98b2d3a","video_url":"https://s3.example.com/aikynetix-media/teams/…/3c613c61-ec7f-42bd-9de3-6577b98b2d3a.source.mp4"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://localhost:8000/api/sessions/probe/ \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "session_id": "3c613c61-ec7f-42bd-9de3-6577b98b2d3a", "video_url": "https://s3.example.com/aikynetix-media/teams/…/3c613c61-ec7f-42bd-9de3-6577b98b2d3a.source.mp4" }'Optional step between the presigned PUT and POST /api/sessions/. Samples ~24 evenly spaced frames and reports what is in the clip, so the caller can SUGGEST the activity, movement and camera plane instead of asking the coach to classify their own video.
Costs no quota. The session-slot debit happens inside session creation, so anything before it is free. There is no 402 on this route.
Never fails your upload. An unreachable inference service, a deploy without the probe, or a clip nothing can decode all answer 200 with person_present: false — the object is already in your bucket, so the caller simply falls back to asking. With the vision read off that answer is also stored: false (nothing is coming). With it on, the row is stored anyway (stored: true, pose_unread: true) because the vision read is independent of the pose read and lands on it a few seconds later — poll the GET.
content_blocked: true is the one answer that decides something. The clip was screened for nudity on our own infrastructure and refused: the object has been DELETED, and POST /api/sessions/ with it answers 400 content_blocked. Nothing else is reported about it. Ask the user to film again in sportswear. Underwear and swimwear are not refused.
Every value is a suggestion, and some are raw signals. plane (side / frontal) is stored but currently unfit to show a user: measured over 226 coach-labelled clips it scored 62% against a 68% always-say-side baseline. The four motion numbers are unitless and body-relative — a treadmill run holds the hips still sideways (median 0.12) where an overground run does not (2.08), and running stays low VERTICALLY (0.10-0.16) where a jump, squat or landing does not (a drop jump reads 0.75-1.63) — published so a consumer can set its own thresholds from its own data rather than trusting one derived here. Nothing on this route decides anything.
vision is present only when a vision model recognised the movement, and is absent otherwise — including on every deployment where the read is switched off. Inside it, only activity is fit to act on: measured on real clips it was right 3/3, while exercise was right 1/3 at the same 0.8-0.9 confidence, so treat the movement name and camera_view as raw signals to grade rather than as answers.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”Body of POST /api/sessions/probe/ — which upload to look at.
Both fields, and checking them AGAINST EACH OTHER is the point: the team
prefix alone would let one coach point the probe at a colleague’s object
key, and session_id is the UUID upload-intent reserved and embedded in
the S3 key, which the caller never chooses.
object
Examples
{ "session_id": "3c613c61-ec7f-42bd-9de3-6577b98b2d3a", "video_url": "https://s3.example.com/aikynetix-media/teams/…/3c613c61-ec7f-42bd-9de3-6577b98b2d3a.source.mp4"}Body of POST /api/sessions/probe/ — which upload to look at.
Both fields, and checking them AGAINST EACH OTHER is the point: the team
prefix alone would let one coach point the probe at a colleague’s object
key, and session_id is the UUID upload-intent reserved and embedded in
the S3 key, which the caller never chooses.
object
Example generated
session_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0&video_url=exampleBody of POST /api/sessions/probe/ — which upload to look at.
Both fields, and checking them AGAINST EACH OTHER is the point: the team
prefix alone would let one coach point the probe at a colleague’s object
key, and session_id is the UUID upload-intent reserved and embedded in
the S3 key, which the caller never chooses.
object
Responses
Section titled “Responses”object
object
object
Examples
A side-view treadmill run
{ "person_present": true, "stored": true, "detection_ratio": 1, "frames_sampled": 24, "plane": "side", "plane_confidence": 1, "facing": "right", "hip_translation": 0.21, "camera_motion": 0.001}A drop jump, with the vision read attached
{ "person_present": true, "stored": true, "detection_ratio": 1, "frames_sampled": 24, "plane": "side", "plane_confidence": 0.9, "facing": "right", "hip_translation": 2.1, "vertical_travel": 1.2, "camera_motion": 0.002, "vision": { "model": "deepseek-v4-flash-vision-exp", "frames": 3, "activity": "jump", "activity_confidence": 0.9, "exercise": "Countermovement Jump", "exercise_confidence": 0.8, "camera_view": "side" }}Nobody in shot, or nothing readable (vision read off)
{ "person_present": false, "stored": false}Pose read failed, vision read still coming
{ "person_present": false, "pose_unread": true, "stored": true}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}