Overview
CheckMotion runs compute-heavy video analysis as a sequence of durable jobs. Start with sport detection or pose extraction, poll the returned job, then pass completed job IDs into downstream analysis endpoints.
1. Submit
2. Poll
COMPLETED or FAILED.3. Compose
Stable machine-readable output
language field localizes human-facing labels and narrative text. Property names, IDs, status values, and taxonomy identifiers remain stable.Authentication
Every endpoint except the health check requires an API key. Create or rotate your key in your CheckMotion account, then send it as a Bearer token.
curl 'https://api-v2.checkmotion.app/health'
curl 'https://api-v2.checkmotion.app/analysis/jobs/JOB_ID' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY'Keep keys server-side
Use HTTPS
Quickstart
This example uploads a tennis clip, receives an asynchronous job, and fetches its localized result.
1. Start sport detection
curl --request POST 'https://api-v2.checkmotion.app/analysis/detect-sport' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY' \
--header 'Accept: application/json' \
--form 'video=@"./serve.mp4"' \
--form 'language=en'2. Save the accepted job
{
"jobId": "124f09f3-b66d-4d3e-96f4-cd9ae84415dc",
"status": "PENDING"
}3. Poll until complete
curl 'https://api-v2.checkmotion.app/analysis/jobs/124f09f3-b66d-4d3e-96f4-cd9ae84415dc' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY'{
"jobId": "124f09f3-b66d-4d3e-96f4-cd9ae84415dc",
"status": "COMPLETED",
"result": {
"sport": "tennis",
"sportLabel": "Tennis",
"confidence": 0.94,
"activityStatus": "resolved",
"movement": {
"id": "tennis:serve",
"type": "serve",
"label": "Serve",
"confidence": 0.88
},
"taxonomyVersion": "checkmotion-activity-taxonomy/1.0"
}
}Async jobs
Long-running work uses a consistent lifecycle. Your integration should persist job IDs and tolerate repeat polling.
PENDING
PROCESSING
COMPLETED
FAILED
Idempotent submission
X-CheckMotion-Job-ID. Reusing that ID returns the existing job instead of creating duplicate work—useful when safely retrying a timed-out request.curl --request POST 'https://api-v2.checkmotion.app/videos/keypoints' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY' \
--header 'X-CheckMotion-Job-ID: 124f09f3-b66d-4d3e-96f4-cd9ae84415dc' \
--form 'video=@"./movement.mp4"'Endpoint reference
All routes are relative to the production base URL. Analysis routes use the analysis job endpoints; pose routes use the general job endpoints.
- POST
/videos/keypointsStart pose extraction - GET
/jobs/{job_id}Get a pose job - GET
/jobs/{job_id}/videoStream the job video - DELETE
/jobs/{job_id}Delete a pose job - POST
/analysis/detect-sportDetect sport and movement - POST
/analysis/generate-detailed-metricsGenerate detailed metrics - POST
/analysis/rate-performanceRate the performance - POST
/analysis/generate-reportGenerate a coaching report - GET
/analysis/jobs/{job_id}Get an analysis job - DELETE
/analysis/jobs/{job_id}Delete an analysis job - POST
/analysis/fullStart the complete pipeline - GET
/analysis/full/{job_id}Get a full-analysis job - POST
/analysis/chatAsk a report-grounded question
Pose extraction
Extract time-aligned pose keypoints from an uploaded recording or a remotely hosted video.
/videos/keypointsStart pose extraction
Send either a multipart video file or a videoUrl, but not both. Remote URLs are validated and must resolve to an allowed HTTPS location.
curl --request POST 'https://api-v2.checkmotion.app/videos/keypoints' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY' \
--form 'videoUrl=https://example.com/private-upload/movement.mp4'/jobs/{job_id}Read pose status and output
Poll this route for pose jobs. Completed responses include the extracted keypoint data. The authorized video-stream route is intended for controlled server-side playback; delete removes the stored job and its associated assets.
Sport detection & localization
Identify the sport and, when evidence is sufficient, resolve the movement against CheckMotion’s versioned activity taxonomy.
/analysis/detect-sportDetect sport and movement
Input
videoUrl, plus an optional BCP 47-style language such as en or de-AT.Output
Do not branch on labels
sport and movement.id. Localized labels are presentation strings and may vary by language.Movement analysis
Combine completed pose and sport jobs to calculate movement-specific metrics, then create a performance rating from those metrics.
/analysis/generate-detailed-metricsGenerate detailed metrics
curl --request POST 'https://api-v2.checkmotion.app/analysis/generate-detailed-metrics' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"keypointJobId": "POSE_JOB_ID",
"sportDetectionJobId": "SPORT_JOB_ID",
"language": "en"
}'/analysis/rate-performanceRate performance
curl --request POST 'https://api-v2.checkmotion.app/analysis/rate-performance' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"detailedMetricsJobId": "METRICS_JOB_ID",
"language": "en"
}'Prerequisites must be complete
COMPLETED. A pending, failed, missing, or incompatible prerequisite returns a structured error.For server-owned orchestration, POST /analysis/full accepts a video together with explicit keypoint and sport-detection job IDs, while GET /analysis/full/{job_id} returns the pipeline state.
Reports & coaching chat
Turn structured analysis into coach-friendly feedback, then let users ask bounded follow-up questions grounded in the completed report.
/analysis/generate-reportGenerate a coaching report
curl --request POST 'https://api-v2.checkmotion.app/analysis/generate-report' \
--header 'Authorization: Bearer cm_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"sportDetectionJobId": "SPORT_JOB_ID",
"detailedMetricsJobId": "METRICS_JOB_ID",
"performanceRatingJobId": "RATING_JOB_ID",
"language": "en"
}'/analysis/chatAsk a grounded question
Chat is synchronous and intentionally bounded. Provide the completed report context and conversation state required by the schema; responses stay focused on the analyzed movement rather than acting as a general-purpose assistant.
Errors & recovery
HTTP status codes communicate the broad outcome. Error bodies add a stable category and context your integration can use for recovery or support.
400 Bad Request
401 Unauthorized
404 Not Found
409 Conflict
422 Unprocessable Entity
429 Too Many Requests
500 Server Error
503 Unavailable
{
"detail": {
"error": "A prerequisite job has not completed",
"error_type": "prerequisite_not_ready",
"error_details": {
"job_id": "POSE_JOB_ID",
"status": "PROCESSING"
}
}
}Retry transient 429, 500, and 503 responses with exponential backoff and jitter. Do not automatically retry validation or authentication failures without changing the request.
