Uploading a video
Three calls, in this order. The middle one does not go to the API at all.
sequenceDiagram
participant You
participant API
participant Storage
You->>API: POST /api/sessions/upload-intent/
API-->>You: session_id + presigned url
You->>Storage: PUT the raw bytes
Note over You,Storage: The video never touches the API
Storage-->>You: 200
You->>API: POST /api/sessions/
API-->>You: 201 pending — quota debited
Why it is three steps
Section titled “Why it is three steps”The video never passes through the API. upload-intent hands you a URL that is
write-only to one object, you PUT the bytes there directly, and then you tell
the API where they landed. Large files never touch the API’s request path.
Formats and size
Section titled “Formats and size”MP4, MOV and WebM. The content_type you declare must be a video/* type (or
application/octet-stream); anything else is rejected when you ask for the
intent.
Up to about 500 MB. That is what the web app enforces and what the presigned URL’s two-hour window is sized for.
Shorter is better. Film the reps you want analysed, not a long clip with idle time either side.
Retrying an upload
Section titled “Retrying an upload”Re-send the same presigned URL. It stays valid for two hours, and the
window is deliberately sized off a slow connection rather than a round trip.
Asking for a fresh intent instead gives you a new session_id, which means the
old one is stranded.
If the create call’s response was lost and you retry it, you will get
{"id": ["session_id_taken"]}. That is the id doing its job — check whether
the session exists before re-creating it.
Creating the session
Section titled “Creating the session”curl -X POST https://api.ai.aikynetix.app/api/sessions/ \ -H 'Authorization: Bearer aik_yourPartnerTokenHere' \ -H 'Content-Type: application/json' \ -d '{ "id": "5c836d7d-3301-49df-bfa0-9cff0550fd0e", "activity": "running", "exercise": "Treadmill", "video_url": "https://s3.ai.aikynetix.app/…/5c836d7d….source.mp4", "client": "3f1a…", "camera_view": "side", "name": "Anna — baseline — side view" }'id is the session_id from the intent; video_url is its public_url.
Passing both back is what keeps the row and the stored object aligned.
Fields that only apply to some activities
Section titled “Fields that only apply to some activities”These are silently dropped where they do not apply, so a multi-activity uploader can always send them:
| Field | Applies to | If omitted |
|---|---|---|
barbell_mass_kg |
weightlifting | Mass-dependent lift metrics are suppressed rather than guessed from an assumed load. |
treadmill_incline_deg |
running, walking | Treated as level ground. |
approach_step_count |
bowling | Auto-detected. |
walk_test_distance_m |
walking / Timed Walk |
Required there — the exercise has no meaning without a measured course. |
handedness |
fencing, tennis, bowling | Assumes right-handed. |
trim |
any | The whole clip is analysed. |
blur_face |
any | No blurring. The raw upload is never anonymised either way. |
Two activities require extra payloads rather than accepting them optionally:
scuba_diving needs its session-meta sidecar, and
workspace_wellness / Ergonomics Assessment needs the workstation survey.
Both are rejected at create time if missing, because neither analysis is
meaningful without them.
- Activities and exercises — the exact strings, and which camera views each pair supports.
- The analysis lifecycle — what happens after the
201.