On this page
Returns every film and episode your organisation may stream right now. The response is metadata only and never contains a video URL; request playback per episode with Request playback.
GET /api/delivery/v1/catalogScope: metadata:read
Description
A film is included when your organisation has an active streaming licence for it, today (UTC) is inside the licence window, and the film is published. For each included film, all published episodes are returned, plus a placeholder row for each planned episode that is not published yet. Films arrive sorted by display_order. There is no pagination. See Catalog.
Request parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | Yes | Bearer <API key>. |
This endpoint takes no query parameters.
Request example
curl -s https://www.wandura.ai/api/delivery/v1/catalog \
-H "Authorization: Bearer $WANDURA_API_KEY"Response
200 OK with an object containing two arrays.
Film fields (films[])
| Field | Type | Description |
|---|---|---|
id |
string (UUID) | Film ID. It never changes: use it as your primary key, and as film_ref in playback. |
title |
string | Film title. |
slug |
string | URL-safe film identifier, unique across films. Wandura does not change it after the film is created. Also accepted as film_ref in playback. |
synopsis_short |
string or null | Short description for cards. Length varies. |
synopsis_full |
string or null | Full description for detail pages. |
genres |
array of strings | Genre labels. Can be empty. |
language |
string or null | Language of the film, as free text written by Wandura's content team (for example en or English). It is not a fixed list of codes: display it, do not parse it. |
poster_url |
string or null | Film poster URL. |
status |
string | Always published. |
display_order |
integer | Display position, smallest first. The array is already sorted by it. |
planned_episodes |
integer or null | Total number of episodes planned. null when not set: then the film gets no placeholder rows, and episodes lists only its published episodes. |
free_until_episode |
integer or null | Episodes with episode_no up to and including this number are free. 0 means no free episode. null means no number is set for the film: treat every episode as paid, and ask Wandura if you expected free episodes. |
audience |
string or null | women, men, lgbtq, or null if unclassified. |
form |
string or null | live_action, anime, or null if unclassified. |
setting |
string or null | modern, city, fantasy, campus, palace, or null if unclassified. |
Episode fields (episodes[])
| Field | Type | Description |
|---|---|---|
id |
string (UUID) or null | Episode ID. Use it as episode_id in playback. null on placeholder rows. |
film_id |
string (UUID) | ID of the film the episode belongs to. |
episode_no |
integer | Episode number, starting at 1. |
title |
string or null | Episode title. |
synopsis |
string or null | Episode description. Often null. |
duration_ms |
integer or null | Duration in milliseconds. |
poster_uri |
string or null | Episode thumbnail reference. Not guaranteed to be a directly loadable URL. |
status |
string | published, or planned for a placeholder row. |
stream_ready |
boolean | true when a ticket can be issued for the episode. Always false on placeholder rows. |
Within a film, each episode_no appears once, so film_id + episode_no identifies an episode. Episodes are grouped by film ID and sorted by episode_no within each film. Take the film order from films.
If your organisation has no current licences, both arrays are empty.
Response example
{
"films": [
{
"id": "3f6c1a52-8d0e-4b7a-9c21-5e4f2a7b9d10",
"title": "The Heiress Returns",
"slug": "the-heiress-returns",
"synopsis_short": "Cast out on her wedding day, a disowned heiress comes back to take everything.",
"synopsis_full": "Cast out on her wedding day, Mia loses her family, her name and her fortune. Five years later she returns with a new identity and one goal.",
"genres": ["romance", "revenge"],
"language": "en",
"poster_url": "https://cdn.example.com/posters/the-heiress-returns.jpg",
"status": "published",
"display_order": 10,
"planned_episodes": 3,
"free_until_episode": 1,
"audience": "women",
"form": "live_action",
"setting": "modern"
}
],
"episodes": [
{
"id": "b2a4d6e8-1c3f-4a5b-8d7e-9f0a1b2c3d4e",
"film_id": "3f6c1a52-8d0e-4b7a-9c21-5e4f2a7b9d10",
"episode_no": 1,
"title": "Episode 1",
"synopsis": null,
"duration_ms": 94000,
"poster_uri": null,
"status": "published",
"stream_ready": true
},
{
"id": "c7d9e1f3-5a6b-4c8d-9e0f-1a2b3c4d5e6f",
"film_id": "3f6c1a52-8d0e-4b7a-9c21-5e4f2a7b9d10",
"episode_no": 2,
"title": "Episode 2",
"synopsis": null,
"duration_ms": 101000,
"poster_uri": null,
"status": "published",
"stream_ready": false
},
{
"id": null,
"film_id": "3f6c1a52-8d0e-4b7a-9c21-5e4f2a7b9d10",
"episode_no": 3,
"title": null,
"synopsis": null,
"duration_ms": null,
"poster_uri": null,
"status": "planned",
"stream_ready": false
}
]
}Errors
| Status | error_code |
When |
|---|---|---|
| 401 | none | The Authorization: Bearer header is missing, or the key is unknown or revoked. |
| 403 | none | The key lacks the metadata:read scope. |
| 403 | none (error is org_suspended) |
Your organisation's access is suspended. |
| 429 | rate_limited |
The rate limit for the catalog and creatives endpoints was reached. |
| 503 | service_unavailable |
Wandura could not verify the API key in time. The key is not wrong: retry after Retry-After seconds, with backoff. |
The two 403 responses carry no error_code. Tell them apart by error: it is exactly org_suspended when your organisation is suspended, and any other text means the key lacks metadata:read. This is the one case where you compare error; compare the whole string.
See Errors for what to do in each case.
Updated 1 Oct 2026 · Change history (2)