Skip to content

Quickstart

This is the whole loop, end to end. Copy it, change the key, and you have a working integration.

Throughout, replace aik_yourPartnerTokenHere with your key.

Optional, and worth doing anyway. Height, weight and gender make the metrics body-aware — green zones, ground reaction forces and anything mass-dependent are scaled to this person. Without an athlete, the analysers fall back to population defaults and the report is measurably vaguer.

Terminal window
curl -X POST https://api.ai.aikynetix.app/api/clients/ \
-H 'Authorization: Bearer aik_yourPartnerTokenHere' \
-H 'Content-Type: application/json' \
-d '{"display_name":"Anna Petrova","gender":"female","height_cm":171,"weight_kg":63.5}'

Keep the returned id. Reuse it for every session for that athlete — that is what makes progress over time readable.

Terminal window
curl -X POST https://api.ai.aikynetix.app/api/sessions/upload-intent/ \
-H 'Authorization: Bearer aik_yourPartnerTokenHere' \
-H 'Content-Type: application/json' \
-d '{"filename":"clip.mp4","content_type":"video/mp4","activity":"running"}'
{
"session_id": "5c836d7d-3301-49df-bfa0-9cff0550fd0e",
"url": "https://s3.ai.aikynetix.app/…?X-Amz-Signature=…",
"method": "PUT",
"headers": { "Content-Type": "video/mp4" },
"public_url": "https://s3.ai.aikynetix.app/…/5c836d7d….source.mp4"
}

You get back a session id reserved for you, and a URL to PUT the bytes to. The URL is write-only to that one object and valid for two hours.

Terminal window
curl -X PUT --upload-file clip.mp4 \
-H 'Content-Type: video/mp4' \
"<the url from step 2>"

This is the call that starts the analysis and debits one session of quota.

Terminal window
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": "<the public_url from step 2>",
"client": "<the client id from step 1>",
"camera_view": "side"
}'

Pass the session_id back as id and the public_url as video_url. That is what keeps the database row and the stored object pointing at each other.

You get a 201 with status: "pending".

poll.py
import time
import requests
HEADERS = {"Authorization": "Bearer aik_yourPartnerTokenHere"}
url = "https://api.ai.aikynetix.app/api/sessions/5c836d7d-3301-49df-bfa0-9cff0550fd0e/"
DEADLINE = time.monotonic() + 600 # give up after 10 minutes
delay = 2.5 # then back off
while True:
r = requests.get(url, headers=HEADERS, timeout=30)
r.raise_for_status()
session = r.json()
if session["status"] in ("completed", "failed"):
break
if time.monotonic() > DEADLINE:
raise TimeoutError(f"still {session['status']} after 10 minutes")
time.sleep(delay)
delay = min(delay * 1.5, 30) # a stuck session must not be hammered
if session["status"] == "failed":
raise RuntimeError(session["failure_reason"])
for metric in session["metrics"]:
print(metric["key"], metric["value_num"])

A typical clip finishes in tens of seconds. See The analysis lifecycle for what the intermediate states mean and how to show progress.

metrics is a list of { key, value_num, value_json }. value_num is always SI — centimetres, metres per second, milliseconds, degrees. metric_targets carries the good range for this athlete, already adjusted for their profile. analyzed_url is the annotated video.

Reading results explains how to interpret all of it.