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.
Create the session soon after the PUT. An upload that no session has claimed
after three days is deleted, and a create after that answers
400 clip_not_found.
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 500 MB and 180 seconds. The PUT itself cannot refuse a bigger file —
a presigned PUT carries no size range — so the check runs when you create the
session: it measures the uploaded object and answers 400 clip_too_large or
clip_too_long (or clip_not_found if the PUT has not finished) before
any quota is touched. With a trim window, the
window is what counts. A trim window must be at least 1 second long
(end_s − start_s ≥ 1); a shorter one is a 400 with a field error under
trim.end_s.
A session that renders with original_quality: true has a shorter duration
ceiling: 30 seconds, measured the same way — on create, and on a re-run that
turns the flag on or keeps it. Over it is the same 400 clip_too_long, with
max_duration_s: 30 — trim the clip, or turn the flag off. Why 30: the
full-resolution render is bounded by frames — it is written at up to 30 fps,
and twice when blur_face is on — and 30 seconds is what fits its frame budget
with both. Read the live value from max_duration_s; it may be raised.
Shorter is better. Film the reps you want analysed, not a long clip with idle time either side — 60 seconds or less is the sweet spot, and shorter clips come back faster. Codecs, resolution and frame rate are covered in Limits and capacity.
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. The
public_url arrives presigned so you can read the object back; send it as it
is — we store it without the signature.
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. |
slow_motion_capture_fps |
american_football / Long Snap |
120 or 240 for a phone slow-motion clip. Omitted on a slow-motion clip, its times and speeds are withheld; on a real-time clip it is not needed. |
camera_distance_m |
the single-leg hops: jump / Single Leg Hop and Return, Single Leg Triple Hop, Single Leg Broad Jump, and the last two under american_football |
The analyzer assumes the recording guide’s protocol distance (2.75 m). Measured lens-to-athlete distance at the start position, 1–20 m, any camera view. |
handedness |
fencing, tennis, bowling | Assumes right-handed. |
trim |
any | The whole clip is analysed. |
blur_face |
any | Blurred: faces are blurred in the analysed video. Send false for no blurring. The raw upload is never blurred either way. |
original_quality |
any | The analysed video comes back at the default 1920-pixel long side. See below. |
original_quality is an optional boolean. true delivers the analysed video
(analyzed_url) at the clip’s own resolution, up to 4K (3840 long side) at up
to 30 fps, instead of the default 1920 long side, at a higher encode quality (a
clip analysed at 60 fps comes back at 30) — for
presentations and marketing material. A Full HD or smaller clip comes back at
its own size (never upscaled). It changes only the video: metrics are not
affected. It costs noticeably more processing time and a file several times
larger, and the clip is held to the 30 seconds ceiling above. The session
read returns original_quality so you can tell the two apart;
POST /api/sessions/{id}/reanalyze/ accepts it too (true / false; omit it
to keep the session’s current choice). The read also says what the last
completed run delivered, original_quality_rendered: false when the video
fell back to the default render (a re-run may succeed), null when the run did
not ask and while no completed run exists, e.g. a re-run in flight
(original_quality_anonymized_rendered is the same for the face-blurred copy).
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.