API reference
Returns one open video you already know, with fresh signed links. row has the same shape as one entry of List open videos, so one parser serves both. It has its own rate-limit counter, separate from the list.
GET /api/delivery/v1/videos/{id}Scope: videos:read, on a key bound to an app
Request parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | Yes | Bearer <API key> for a key with the videos:read scope. |
id |
path | string (UUID) | Yes | The video id from the list endpoint. Not the slug, and not order_code. |
Request example
curl -s https://www.wandura.ai/api/delivery/v1/videos/c7d9e1f3-5a6b-4c8d-9e0f-1a2b3c4d5e6f \
-H "Authorization: Bearer $WANDURA_API_KEY"id is the id from the list: not the slug, not the order_code.
Response
200 OK. New fields may be added at any time: ignore the ones you do not recognise.
| Field | Type | Description |
|---|---|---|
row |
object | Same shape as one entry of rows[] in the list endpoint. |
collections |
array of strings | Every granted collection this video belongs to. row.collection is the first of them. |
expires_at |
string (ISO 8601, UTC) | |
refresh_before |
string (ISO 8601, UTC) |
Response example
{
"row": {
"id": "3f6c1a52-8d0e-4b7a-9c21-5e4f2a7b9d10",
"slug": "dead-bug",
"title": "Dead bug",
"order_code": null,
"collection": "abs-program",
"position": 4,
"duration_ms": 42000,
"muscle_groups": ["core"],
"equipment": [],
"difficulty": "beginner",
"kcal_est": null,
"mp4": { "p480": "https://fit-playback.wandura.ai/…/480.mp4?auth_key=…", "p720": null }
},
"collections": ["abs-program"],
"expires_at": "2026-10-02T13:00:00.000Z",
"refresh_before": "2026-10-02T12:45:00.000Z"
}Response headers
| Header | Responses | Description |
|---|---|---|
Wandura-API-Status |
all | API status. beta today, on every response, success or error. |
Wandura-Request-Id |
all | An opaque id for this request (req_ followed by 26 characters). Every response carries it, errors included, and error bodies repeat it as request_id. Log it, and quote it when you contact Wandura about a request: it finds the exact request in our logs. Do not parse it. |
Cache-Control |
all | Always no-store. Do not cache these responses in shared caches. |
Wandura-Version |
400, 401, 403, 404, 429, 500, 503 | The dated API version (YYYY-MM-DD) this response was produced in: the version pinned to your API key, or the one you sent in the Wandura-Version request header. Keys created before dated versions existed use 2026-10-02. |
Retry-After |
429, 503 | Seconds to wait before retrying. Sent with 429 and with retryable 503 responses. |
X-RateLimit-Limit |
429 | Requests (for playback, tickets) allowed per window for this endpoint group and your organisation. |
X-RateLimit-Window |
429 | Window length in seconds. |
Errors
| Status | error_code |
When |
|---|---|---|
| 400 | none | id in the path is not a uuid. |
| 400 | unsupported_version |
The Wandura-Version header, or the version pinned to your key, is unknown or retired. The body adds supported_versions and latest_version (and upgrade_to when your pin was retired). |
| 401 | none | The Authorization: Bearer header is missing, or the key is unknown or revoked. |
| 403 | none | The key lacks the videos:read scope. |
| 403 | none (error is app_not_registered) |
The key is not bound to an app. Register the app on the Developers page and use that app's key. |
| 403 | none (error is org_suspended) |
Your organisation's access is suspended. |
| 404 | none (error is video_not_found) |
Unknown, not granted, not published, archived, or not playable yet. |
| 429 | rate_limited |
The rate limit for this endpoint was reached. It is counted separately from the list endpoint. |
| 500 | none | The video could not be read. Retry with backoff. |
| 503 | service_unavailable |
Wandura could not verify the API key in time. The key is not wrong: retry after Retry-After seconds, with backoff. |
What to do for each: Errors.
Updated 5 Oct 2026 · Change history (2)