Skip to content

Activities and exercises

activity is an enum key — running, walking, weightlifting, workspace_wellness, ice_hockey. exercise is the catalogue label within it — Treadmill, Back Squat, Overhead Squat.

Matching is exact. "Overhead Squat" works. "overhead squat" does not, and neither does "Overhead squat". There are 21 activities and 107 valid pairs.

Terminal window
curl -H 'Authorization: Bearer aik_yourPartnerTokenHere' \
'https://api.ai.aikynetix.app/api/exercises/?activity=running'

The response carries everything you need to build an upload UI without hardcoding anything:

Field What it gives you
presets The valid exercise strings for that activity.
views_by_exercise Which camera views each pair supports.
guide / guides_by_exercise How to film it — camera position, distance, duration.
metrics The metric specs each pair emits: key, label, unit, description, higher_is_better, the default good range (min_good / max_good) and amber band (amber_low / amber_high), has_series, beta (not yet validated) and exclude_from_score. The metric dictionary lists them all.

Omit ?activity= to get the whole catalogue grouped under by_activity.

The catalogue grows. Activities and exercises are added regularly. An integration that reads this endpoint picks them up for free; one that hardcodes a list quietly stops offering the new ones.

Some contracts cover a named list of movements rather than the whole catalogue — four jumps and an overhead squat, say. For those, this endpoint returns only the movements the contract covers: presets, metrics and views_by_exercise are narrowed, and an activity with nothing left drops out of by_activity entirely. Contracts without a named list see everything.

Creating a session on any other pair — one that exists in the catalogue but not in the contract — answers 402 with detail: "exercise_not_in_plan", before any quota is touched. The same code comes back for an upload with no exercise unless the contract covers that whole activity: the activity-default analysis is the whole activity, which is exactly what a named list does not include. So if presets for an activity is shorter than you expected, always send an exercise from it rather than the bare activity.

GET /api/movement-guide/ follows the same rule: a movement outside the contract reads as having no guide (404), the same as a pair that never had one.

The response carries no “this is a narrowed list” flag — the contract is the list. An integration that offers only what this endpoint returns never sees exercise_not_in_plan; see Errors for how to handle it if a hardcoded list slips through.

Each pair supports a specific set of side / front / back. Sending an unsupported plane is rejected at create time:

{
"camera_view": "'side' is not a supported camera view for '4-Stage Balance' …",
"code": "unsupported_camera_view",
"supported_views": ["front"]
}

That rejection is deliberate and recent. Before it existed, an unsupported view would create the session, debit quota, and complete with zero metrics — the sagittal analyser simply has no dispatch for a front-only movement. A 400 is much better than an empty report you paid for.

Branch on code, not the prose, and use supported_views to tell the user what to do.

The guide fields carry per-activity and per-exercise recording instructions — camera height, distance, duration, lighting, clothing. They are the same instructions the upload wizard shows a coach, and following them is the single biggest lever on whether the resulting numbers are worth anything.

The Help section covers the general principles.