Skip to content

Describe a just-uploaded clip, before it becomes a session

POST
/api/sessions/probe/
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.

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
session_id
required
string format: uuid
video_url
required
string
>= 1 characters <= 1000 characters

Examples

ExampleRequest
{
"session_id": "3c613c61-ec7f-42bd-9de3-6577b98b2d3a",
"video_url": "https://s3.example.com/aikynetix-media/teams/…/3c613c61-ec7f-42bd-9de3-6577b98b2d3a.source.mp4"
}
Media typeapplication/json
object
vision
object
model
required
string
frames
required
integer
activity
required
string
activity_confidence
required
number format: double
exercise
required
string
nullable
exercise_confidence
required
number format: double
camera_view
required
string
nullable
exercise_candidates
Array<object>
object
name
required
string
confidence
required
number format: double
person_present
required
boolean
stored
required
boolean
pose_unread
boolean
detection_ratio
number format: double
frames_sampled
integer
plane
string
nullable
plane_confidence
number format: double
facing
string
nullable
hip_translation
number format: double
vertical_travel
number format: double
direction_changes
integer
camera_motion
number format: double
content_blocked
boolean

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
}
Media typeapplication/json
object
detail
required

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).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

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).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

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).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

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).

string

Example generated

{
"detail": "example"
}