# Creatives

The creatives feed gives your marketing systems a long-term data record for each ad creative your organisation has approved on Wandura. Each record says what the creative is: the film, the episodes and scenes it uses, its format and duration, its hook, the formula it was built with and when your rights to use the film end. Your systems store these records and decide which creatives to use and how.

## What the feed contains

The feed returns creatives that belong to your organisation and have status `approved` or `pushed` (already delivered). Creatives in any other status, such as drafts, are not included. Creatives of other organisations are never visible.

A record never contains a media URL. The feed describes the creative; final video files are not delivered through this API. Ask Wandura how final files reach your systems.

`final.ready` tells you whether the final render of the creative exists yet.

## Endpoints

| Endpoint | Use |
|---|---|
| [`GET /api/delivery/v1/creatives`](https://docs.wandura.ai/developers/reference/creatives-list) | Sync all records, incrementally. |
| [`GET /api/delivery/v1/creatives/{id}`](https://docs.wandura.ai/developers/reference/creatives-get) | Fetch or re-check one record. |

Both need a key with the `creatives:export` scope, which you can create yourself on the **Developers** page of the partner portal. See [Authentication](https://docs.wandura.ai/developers/authentication).

## Response envelope

Unlike the catalog and playback endpoints, the creatives endpoints wrap every response in an envelope:

```json
{
  "code": 0,
  "message": "ok",
  "data": { "items": [], "next_cursor": null },
  "server_time": 1790679032
}
```

`code` is `0` on success and a four-digit error code otherwise. Timestamps in this feed, including `server_time`, are Unix epoch seconds. See [Errors](https://docs.wandura.ai/developers/concepts/errors).

## Syncing incrementally

Records are returned oldest update first, ordered by `updated_at` and then by ID, so new updates never shift pages you have already read.

1. **First sync.** Call `GET /creatives?limit=100` without `updated_since`. While `data.next_cursor` is not `null`, call again with `cursor=<next_cursor>`.
2. **Save a checkpoint.** Keep the largest `updated_at` you received.
3. **Later syncs.** Call with `updated_since=<checkpoint>` and page through with `cursor` again. Only records updated strictly after that second (`>`) are returned.

```bash
curl -s "https://www.wandura.ai/api/delivery/v1/creatives?updated_since=1790600000&limit=100" \
  -H "Authorization: Bearer $WANDURA_API_KEY"
```

`updated_at` is rounded down to the second, so a record can appear again in the next sync. Store records keyed by `creative_id` and overwrite on repeat.

Treat `cursor` values as opaque. Pass them back exactly as received.

### Creatives that leave the feed

The feed has no deletion events. If a creative stops being approved, it simply stops appearing. To confirm that a stored creative is still available, call `GET /creatives/{id}`: it returns `404` (`code` `4040`) for a creative that is no longer in the feed.

## The record

The main fields of a record are below. The full list, with types, is in the [list creatives reference](https://docs.wandura.ai/developers/reference/creatives-list#the-creative-record).

| Field | What it tells you |
|---|---|
| `creative_id` | Stable ID of the creative. Use it as your primary key. |
| `creative_code` | Immutable human-readable code of the creative. Treat it as an opaque string. |
| `film` | Film code, title, language and genres. |
| `episodes` | Episode numbers the creative uses. |
| `scenes` | Each clip used: episode number, start and end in milliseconds, action label and spoken line. |
| `hook` | The action label and line of the opening scene. |
| `placement`, `aspect` | Ad placement (`reels_9x16`, `feed_4x5` or `square_1x1`) and its aspect ratio. |
| `duration_ms` | Total length of the clips used. |
| `formula` | The formula the creative was built with, if any. |
| `rights.ends_at` | The last day of your export rights for the film (00:00 UTC of that day), or `null`. |
| `lineage.parent_creative_id` | The creative this one was derived from, if any. |
| `final.ready` | Whether the final render exists. |

`rights.ends_at` is 00:00 UTC of the last day of your export rights for the film. That day is included: stop using the creative after that UTC day ends, at `ends_at + 86400`.

## Versioning

Each record carries `schema_version`, currently `1`. New fields can be added without changing it, so ignore fields you do not recognise.

## Rate limits

The two creatives endpoints share one rate-limit counter, separate from the catalog. A sync a few times an hour is well within it. See [Rate limits](https://docs.wandura.ai/developers/concepts/rate-limits).
