Change history
Every change to this page, newest first. Expand an entry to see what changed.
- 2 Oct 2026 · +25 −102 lines
Show changes
# API reference - The Wandura Delivery API lets your backend read the films you are licensed for, request playback for one episode at a time, and sync approved ad creatives. This section documents each endpoint. For the integration flow, start with the [Quickstart](../quickstart.md), [Authentication](../authentication.md) and [Playback](../concepts/playback.md). + The reference documents each endpoint of the Wandura Delivery API: parameters, fields, examples, headers and errors, generated from the OpenAPI description. The rules shared by every endpoint — authentication, pagination, ticket lifetime, freshness, retries, rate limits, versioning — are on [Canonical API behaviour](behaviour.md). - ## Base URL + ## Base URL {#base-url} ``` ⋯ ``` - Always call `www.wandura.ai`. The bare domain `wandura.ai` answers every request with a `308` redirect to `www`, and some HTTP clients drop the body or headers of a `POST` when they follow a redirect. + Always `www.wandura.ai`. The bare domain answers `308` to `www`, and some HTTP clients drop the body or headers of a `POST` when they follow a redirect. - ## Endpoints + ## Endpoints {#endpoints} | Method | Path | Scope | Page | |---|---|---|---| | `GET` | `/api/delivery/v1/catalog` | `metadata:read` | [List licensed catalog](catalog.md) | - | `GET` | `/api/delivery/v1/config` | `any` | Get configuration | + | `GET` | `/api/delivery/v1/config` | `any` | [Get configuration](config.md) | | `GET` | `/api/delivery/v1/creatives` | `creatives:export` | [List creatives](creatives-list.md) | | `GET` | `/api/delivery/v1/creatives/{id}` | `creatives:export` | [Get a creative](creatives-get.md) | | `POST` | `/api/delivery/v1/playback` | `playback` | [Request playback](playback.md) | - | `GET` | `/api/delivery/v1/videos` | `videos:read` | [List open videos](../open-video.md) | - | `GET` | `/api/delivery/v1/videos/{id}` | `videos:read` | One open video with a fresh playback link | - - `GET /api/delivery/v1/config` — [Get configuration](config.md), callable with any valid key. + | `GET` | `/api/delivery/v1/videos` | `videos:read` | [List open videos](videos-list.md) | + | `GET` | `/api/delivery/v1/videos/{id}` | `videos:read` | [One open video with a fresh playback link](videos-get.md) | - Any other path under `/api/delivery/v1/`, with any method, returns `404` with a flat JSON body and `error_code` `not_found`. If you get it on a path you expected to work, check the path for a typo. + Any other path under `/api/delivery/v1/` answers `404` `not_found`; a real path with the wrong method answers `405`. Machine-readable contract: the OpenAPI 3 description of every endpoint above is published at [https://docs.wandura.ai/developers/openapi/delivery-v1.json](https://docs.wandura.ai/developers/openapi/delivery-v1.json). Use it to generate a client or to validate your integration. It changes only additively within `/v1`. - ## Server-to-server only - - Call these endpoints from your backend, never from a browser or a mobile app. They do not send CORS headers, and your API key must never ship inside a client. - - ## Authentication - - Send your API key as a bearer token on every request: - - ``` - Authorization: Bearer <your API key> - ``` - - Each key belongs to one organisation and carries one or more scopes. A missing, unknown or revoked key gets `401`. A valid key that lacks the endpoint's scope gets `403`. + ## Server-to-server only {#server-to-server-only} - | Scope | Grants | How you get it | - |---|---|---| - | `metadata:read` | [List licensed catalog](catalog.md) | Create it yourself in the partner portal | - | `creatives:export` | [List creatives](creatives-list.md), [Get a creative](creatives-get.md) | Create it yourself in the partner portal | - | `webhooks:manage` | Not used by any endpoint yet | Create it yourself in the partner portal | - | `playback` | [Request playback](playback.md) | Create it yourself in the partner portal (**Stream films in an app**) | + Call these endpoints from your backend, never from a browser or an app: they send no CORS headers, and a key inside a client can be extracted. See [Security](../concepts/security.md). - Organisation members with the **Admin** or **Developer** role create, rotate and revoke keys on the **Developers** page of the partner portal. The full key is shown once, at creation. This includes keys with the `playback` scope: if one leaks, anyone can stream your licensed films, so revoke it immediately. See [Authentication](../authentication.md). + ## Requests and responses {#requests-and-responses} - ## Versioning + - Bodies are JSON. Send `Content-Type: application/json` on `POST`. + - Film, episode, creative and video IDs are UUID strings. + - Times are ISO 8601 UTC strings (`expires_at`), except in the creatives feed, which uses Unix epoch seconds. + - Every response carries `Wandura-Version` and `Wandura-API-Status: beta`. + - Ignore fields, values and error codes you do not recognise: see [Versioning and API evolution](../concepts/versioning.md#tolerant-reader). - The API version is part of the path (`/v1`). Within a version, Wandura may add new response fields and new error codes without notice. Ignore fields you do not recognise, and always keep a default branch for unknown error codes. What counts as breaking, and how long old versions are supported: [Versioning and deprecation](../concepts/versioning.md). + ## Where the shared rules live {#shared-rules} - Creative records also carry a `schema_version` field, currently `1`. Additive fields do not change it. + | Topic | Page | + |---|---| + | Keys, scopes | [Authentication](../authentication.md) | + | Pagination, tickets, freshness, retries, rate limits, versioning | [Canonical API behaviour](behaviour.md) | + | Every error, per endpoint | [Errors](../concepts/errors.md) | + | Rate limits under load | [Rate limits](../concepts/rate-limits.md) | + | Dated versions, deprecations | [Versioning and API evolution](../concepts/versioning.md) | ### Beta {#beta} - The API is in **beta**. Every response from `/v1` carries the header `Wandura-API-Status: beta`. During the beta Wandura may still change behaviour inside `/v1`; changes are listed in the **Changelog** (link at the bottom of every page). Spotted something wrong or missing? Use **Send feedback** at the top of any docs page. - - ## Requests and responses - - - Request and response bodies are JSON. Send `Content-Type: application/json` on `POST`. - - Film, episode and creative IDs are UUID strings. - - Playback returns `expires_at` as an ISO 8601 timestamp in UTC. The creatives endpoints return timestamps as Unix epoch seconds. - - The creatives endpoints send `Cache-Control: no-store`. Do not cache their responses in shared caches. - - ## Pagination - - Only [List creatives](creatives-list.md) is paginated. It uses an opaque `cursor` and returns `next_cursor` until there are no more records. [List licensed catalog](catalog.md) returns your whole catalog in one response. - - ## Errors - - The API uses two error formats. The catalog and playback endpoints return a flat object: - - ```json - { - "error": "Episode not found or not ready to stream", - "error_code": "not_ready" - } - ``` - - | Field | Type | Description | - |---|---|---| - | `error` | string | Human-readable message. Do not parse it. One exception: a catalog `403` has no `error_code`, and its `error` is exactly `org_suspended` when your organisation is suspended. See [List licensed catalog](catalog.md#errors). | - | `error_code` | string | Machine-readable code. Branch on this. Absent on some errors, for example `401`. | - | `reason` | string | Present with `not_entitled`. The detailed reason, for logs and support. | - - The creatives endpoints wrap every response, success or error, in an envelope with a numeric `code`: - - ```json - { - "code": 4011, - "message": "Invalid or revoked API key", - "server_time": 1790679032 - } - ``` - - | Field | Type | Description | - |---|---|---| - | `code` | integer | `0` on success. A four-digit error code otherwise. | - | `message` | string | `"ok"` on success, a human-readable message otherwise. | - | `data` | object | Present on success only. | - | `server_time` | integer | Server time in Unix epoch seconds. | - - Each endpoint page lists its errors. For retry guidance and the full list, see [Errors](../concepts/errors.md). - - ## Rate limits - - Each organisation has an abuse ceiling per endpoint group, counted over a fixed 60-second window: 10,800 playback requests (about 180 tickets per second), 3,000 catalog requests and 3,000 creatives requests, each on its own counter. Reaching a ceiling usually means a runaway loop. Wandura can raise any of them for your organisation on request, effective within about a minute. The limit headers below appear only on `429` responses. - - When you reach it, every endpoint answers `429` with a flat body, including the creatives endpoints: - - ```json - { - "error": "Too many playback requests for this account. This is an abuse ceiling, not a quota — if a normal integration reaches it, contact us and it will be raised.", - "error_code": "rate_limited" - } - ``` - - | Header | Description | - |---|---| - | `Retry-After` | Seconds until the current window resets. | - | `X-RateLimit-Limit` | Requests allowed per window for this endpoint group. | - | `X-RateLimit-Window` | Window length in seconds. | - - Wait for `Retry-After` before retrying. See [Rate limits](../concepts/rate-limits.md#limits). + The API is in **beta**. During the beta Wandura may still change behaviour inside `/v1`, under the [beta rule](../concepts/versioning.md#beta); every change is in the changelog.
- 2 Oct 2026 · +1 −0 lines
Show changes
⋯ | `POST` | `/api/delivery/v1/playback` | `playback` | [Request playback](playback.md) | | `GET` | `/api/delivery/v1/videos` | `videos:read` | [List open videos](../open-video.md) | + | `GET` | `/api/delivery/v1/videos/{id}` | `videos:read` | One open video with a fresh playback link | `GET /api/delivery/v1/config` — [Get configuration](config.md), callable with any valid key. ⋯
- 2 Oct 2026 · +2 −1 lines
Show changes
⋯ |---|---|---|---| | `GET` | `/api/delivery/v1/catalog` | `metadata:read` | [List licensed catalog](catalog.md) | + | `GET` | `/api/delivery/v1/config` | `any` | Get configuration | | `GET` | `/api/delivery/v1/creatives` | `creatives:export` | [List creatives](creatives-list.md) | | `GET` | `/api/delivery/v1/creatives/{id}` | `creatives:export` | [Get a creative](creatives-get.md) | ⋯ | `GET` | `/api/delivery/v1/videos` | `videos:read` | [List open videos](../open-video.md) | - **Rolling out:** `GET /api/delivery/v1/config` — [Get configuration](config.md), callable with any valid key. + `GET /api/delivery/v1/config` — [Get configuration](config.md), callable with any valid key. Any other path under `/api/delivery/v1/`, with any method, returns `404` with a flat JSON body and `error_code` `not_found`. If you get it on a path you expected to work, check the path for a typo. ⋯
- 2 Oct 2026 · +4 −1 lines
Show changes
⋯ |---|---|---|---| | `GET` | `/api/delivery/v1/catalog` | `metadata:read` | [List licensed catalog](catalog.md) | - | `POST` | `/api/delivery/v1/playback` | `playback` | [Request playback](playback.md) | | `GET` | `/api/delivery/v1/creatives` | `creatives:export` | [List creatives](creatives-list.md) | | `GET` | `/api/delivery/v1/creatives/{id}` | `creatives:export` | [Get a creative](creatives-get.md) | + | `POST` | `/api/delivery/v1/playback` | `playback` | [Request playback](playback.md) | + | `GET` | `/api/delivery/v1/videos` | `videos:read` | [List open videos](../open-video.md) | **Rolling out:** `GET /api/delivery/v1/config` — [Get configuration](config.md), callable with any valid key. ⋯ Any other path under `/api/delivery/v1/`, with any method, returns `404` with a flat JSON body and `error_code` `not_found`. If you get it on a path you expected to work, check the path for a typo. + Machine-readable contract: the OpenAPI 3 description of every endpoint above is published at [https://docs.wandura.ai/developers/openapi/delivery-v1.json](https://docs.wandura.ai/developers/openapi/delivery-v1.json). Use it to generate a client or to validate your integration. It changes only additively within `/v1`. + ## Server-to-server only ⋯
- 2 Oct 2026 · +2 −0 lines
Show changes
⋯ | `GET` | `/api/delivery/v1/creatives/{id}` | `creatives:export` | [Get a creative](creatives-get.md) | + **Rolling out:** `GET /api/delivery/v1/config` — [Get configuration](config.md), callable with any valid key. + Any other path under `/api/delivery/v1/`, with any method, returns `404` with a flat JSON body and `error_code` `not_found`. If you get it on a path you expected to work, check the path for a typo. ⋯
- 2 Oct 2026 · Page created