# Liệt kê creative

Trả về một trang các creative đã duyệt của tổ chức bạn, mỗi creative là một bản ghi dữ liệu đầy đủ. Dùng endpoint này để đồng bộ creative vào hệ thống marketing, theo kiểu incremental với `updated_since`.

```
GET /api/delivery/v1/creatives
```

**Scope:** `creatives:export`

## Mô tả
Trả về các creative của tổ chức bạn có status `approved` hoặc `pushed`, sắp theo `updated_at` tăng dần rồi theo ID. Bản ghi không bao giờ chứa URL media. Response thành công được bọc trong envelope `{code, message, data, server_time}`; lỗi dùng cùng envelope đó nhưng không có `data`, trừ `429` và `400` `unsupported_version`, hai lỗi này dùng định dạng phẳng. Xem [Creative](https://docs.wandura.ai/vi/v1/developers/concepts/creatives).

## Tham số request
| Tên | Vị trí | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
| `Authorization` | header | string | Có | `Bearer <API key>` của một key có scope `creatives:export`. |
| `updated_since` | query | integer | Không | Giây Unix epoch (tối đa 11 chữ số). Chỉ trả về bản ghi có thời điểm cập nhật chính xác lớn hơn hẳn giây này (`>`, không phải `>=`). |
| `cursor` | query | string | Không | `next_cursor` của trang trước. Opaque; truyền lại nguyên vẹn. |
| `limit` | query | integer | Không | Số bản ghi mỗi trang, từ 1 đến 100. Mặc định `50`. |
| `Wandura-Version` | header | string | Không | Tuỳ chọn. Một phiên bản API theo ngày (YYYY-MM-DD) dùng cho request này thay cho bản ghim vào API key của bạn. Giá trị lạ hoặc đã ngừng trả 400 với `error_code` `unsupported_version`. |

Bạn có thể kết hợp `updated_since` và `cursor`. Giữ nguyên `updated_since` trên mọi trang của cùng một lần đồng bộ. Vì `updated_at` trong mỗi bản ghi được làm tròn xuống theo giây, truyền `updated_at` lớn nhất bạn đã nhận thường trả lại vài bản ghi cuối; hãy ghi đè chúng theo `creative_id`.

## Ví dụ request
```bash
curl -s "https://www.wandura.ai/api/delivery/v1/creatives?updated_since=1790600000&limit=2" \
  -H "Authorization: Bearer $WANDURA_API_KEY"
```

## Response
`200 OK`

| Trường | Kiểu | Mô tả |
|---|---|---|
| `code` | integer | `0`. |
| `message` | string | `"ok"`. |
| `data.items` | array | Các bản ghi creative trên trang này. |
| `data.next_cursor` | string hoặc null | Truyền làm `cursor` để lấy trang kế tiếp. `null` ở trang cuối. |
| `server_time` | integer | Giờ server tính bằng giây Unix epoch. |
| `links` | object | URL tuyệt đối dựng sẵn của trang này — đi theo `links.next` thay vì tự ráp URL trang kế. |
| `links.self` | string | Chính request này. |
| `links.next` | string hoặc null | Trang sau, hoặc `null` ở trang cuối. |

### Bản ghi creative
[Lấy một creative](https://docs.wandura.ai/vi/v1/developers/reference/creatives-get) trả về cùng bản ghi này.

| Trường | Kiểu | Mô tả |
|---|---|---|
| `links` | object | URL tuyệt đối dựng sẵn tới endpoint của chính creative này (link API, không phải URL media). |
| `schema_version` | integer | Phiên bản schema của bản ghi. Hiện là `1`. Thêm trường mới không làm đổi số này. |
| `creative_id` | string (UUID) | ID ổn định của creative. |
| `creative_code` | string hoặc null | Mã đọc được, không đổi. Coi nó là opaque. |
| `name` | string | Tên creative. |
| `status` | string | `approved`, hoặc `pushed` khi đã giao. |
| `created_at` | integer | Thời điểm tạo, giây Unix. |
| `approved_at` | integer hoặc null | Thời điểm duyệt, giây Unix. |
| `updated_at` | integer | Lần cập nhật gần nhất, giây Unix, làm tròn xuống. |
| `org.slug` | string | Slug của tổ chức bạn. |
| `film` | object hoặc null | Phim mà creative được cắt từ đó. |
| `film.code` | string hoặc null | Mã phim. |
| `film.title` | string hoặc null | Tên phim. |
| `film.language` | string hoặc null | Ngôn ngữ của phim. |
| `film.genres` | mảng string | Thể loại phim. Có thể rỗng. |
| `episodes` | mảng integer | Số thứ tự các tập được dùng, không trùng lặp. |
| `placement` | string hoặc null | `reels_9x16`, `feed_4x5` hoặc `square_1x1`. |
| `aspect` | string hoặc null | `9:16`, `4:5` hoặc `1:1`, khớp với `placement`. |
| `duration_ms` | integer | Tổng độ dài các clip phim được dùng, tính bằng mili giây. Có thể ngắn hơn video hoàn chỉnh, vì `scenes` chỉ liệt kê các clip lấy từ tập phim. |
| `scenes` | array | Các clip phim được dùng, theo thứ tự. |
| `scenes[].episode_no` | integer hoặc null | Tập chứa clip. |
| `scenes[].start_ms` | integer | Điểm bắt đầu clip trong tập, mili giây. |
| `scenes[].end_ms` | integer | Điểm kết thúc clip trong tập, mili giây. |
| `scenes[].duration_ms` | integer | Độ dài clip, mili giây. |
| `scenes[].action` | string hoặc null | Nhãn hành động của cảnh, ví dụ `reveal`, `argue`, `slap`, `kiss`, `embrace`, `cry`, `kneel`, `walk_away` hoặc `violence`. `null` khi cảnh không có hành động đáng chú ý. Có thể có nhãn mới được thêm vào. |
| `scenes[].line` | string hoặc null | Câu thoại hoặc câu nổi bật của cảnh. |
| `hook` | object hoặc null | `action` và `line` của cảnh đầu tiên. `null` khi không có cảnh nào. |
| `formula` | object hoặc null | Formula dùng để dựng creative. |
| `formula.name` | string | Tên formula. |
| `rights.ends_at` | integer hoặc null | Ngày cuối cùng của quyền export phim, dạng giây Unix tại 00:00 UTC của ngày đó. Quyền của bạn gồm trọn ngày đó: ngừng dùng creative sau khi ngày UTC đó kết thúc, tức tại `ends_at + 86400`. `null` khi Wandura không có ngày kết thúc nào được ghi nhận cho quyền export của bạn. |
| `lineage.parent_creative_id` | string (UUID) hoặc null | Creative gốc mà creative này được phái sinh từ đó. |
| `final.ready` | boolean | Bản render hoàn chỉnh đã có hay chưa. Creative ở trạng thái `pushed` luôn đã có. |
| `final.target` | object | Thông số render đích: `width`, `height`, `fps`, `codec`. Hiện giống nhau cho mọi creative (1080 × 1920, 30 fps, `h264`) và không theo `placement`, nên đừng suy khung hình từ nó. |

`scenes` chỉ liệt kê các clip lấy từ tập phim. Các thành phần khác của creative không được liệt kê, nên `duration_ms` có thể ngắn hơn video hoàn chỉnh.

## Ví dụ response
```json
{
  "code": 0,
  "message": "ok",
  "data": {
    "items": [
      {
        "schema_version": 1,
        "creative_id": "5e1b7c3a-2d4f-4a6b-9c8d-0e1f2a3b4c5d",
        "creative_code": "ACV001-FILM0001-EP1-2-F1-TEAM",
        "name": "Heiress returns - wedding hook",
        "status": "approved",
        "created_at": 1790500000,
        "approved_at": 1790590000,
        "updated_at": 1790610000,
        "org": { "slug": "your-org" },
        "film": { "code": "FILM0001", "title": "The Heiress Returns", "language": "en", "genres": ["romance", "revenge"] },
        "episodes": [1, 2],
        "placement": "reels_9x16",
        "aspect": "9:16",
        "duration_ms": 21500,
        "scenes": [
          {
            "episode_no": 1,
            "start_ms": 12000,
            "end_ms": 19500,
            "duration_ms": 7500,
            "action": "reveal",
            "line": "You threw me out. Now watch me take it all back."
          },
          { "episode_no": 2, "start_ms": 40000, "end_ms": 54000, "duration_ms": 14000, "action": null, "line": null }
        ],
        "hook": { "action": "reveal", "line": "You threw me out. Now watch me take it all back." },
        "formula": { "name": "Cliffhanger opener" },
        "rights": { "ends_at": 1798675200 },
        "lineage": { "parent_creative_id": null },
        "final": { "ready": true, "target": { "width": 1080, "height": 1920, "fps": 30, "codec": "h264" } }
      }
    ],
    "next_cursor": "eyJwIjoiZXhhbXBsZS1jdXJzb3IifQ"
  },
  "server_time": 1790679032
}
```

## Header của response
| Header | Response | Mô tả |
|---|---|---|
| `Wandura-API-Status` | mọi response | Trạng thái API. Hiện là `beta`, ở mọi response, thành công hay lỗi. |
| `Wandura-Version` | mọi response | Phiên bản API theo ngày (YYYY-MM-DD) mà response này dùng: bản ghim vào API key của bạn, hoặc bản bạn gửi trong header request `Wandura-Version`. Key tạo trước khi có phiên bản ngày dùng `2026-10-02`. |
| `Wandura-Request-Id` | mọi response | Mã định danh mờ của request này (`req_` và 26 ký tự). Mọi response đều có, kể cả lỗi, và body lỗi lặp lại nó ở `request_id`. Hãy ghi log nó, và gửi kèm khi liên hệ Wandura về một request: nó tìm đúng request đó trong log của chúng tôi. Đừng phân tích chuỗi này. |
| `Deprecation` | 200 | Chỉ có khi endpoint này, hoặc phiên bản ngày đang phục vụ response, đã bị ngừng hỗ trợ (RFC 9745): `@<giây unix>` của ngày ngừng. Hãy ghi nó vào hệ giám sát. |
| `Sunset` | 200 | Chỉ có khi endpoint hay phiên bản ngày đã bị ngừng có ngày thôi chạy (RFC 8594), dạng ngày HTTP. |
| `Link` | 200 | Có kèm `Deprecation`: `<https://docs.wandura.ai/…>; rel="deprecation"` (và `rel="sunset"`) trỏ tới trang giải thích dùng gì thay thế. |
| `Cache-Control` | mọi response | Luôn là `no-store`. Đừng lưu các response này trong cache dùng chung. |
| `Retry-After` | 429 | Số giây cần chờ trước khi thử lại. Có ở response 429 và các response 503 nên thử lại. |
| `X-RateLimit-Limit` | 429 | Số request (với playback là số vé) được phép trong một cửa sổ cho nhóm endpoint này và tổ chức của bạn. |
| `X-RateLimit-Window` | 429 | Độ dài cửa sổ tính bằng giây. |

## Lỗi
| Status | `code` | Khi nào |
|---|---|---|
| 400 | không có | Header `Wandura-Version`, hoặc bản ghim của key, là bản lạ hay đã ngừng. Body có thêm `supported_versions` và `latest_version` (và `upgrade_to` khi bản ghim đã ngừng). |
| 401 | 4010 | Thiếu header `Authorization: Bearer`. |
| 401 | 4011 | Key không tồn tại hoặc đã bị thu hồi. |
| 403 | 4030 | Key thiếu scope `creatives:export`. |
| 403 | 4031 | Quyền truy cập của tổ chức bạn đang bị tạm ngưng. |
| 422 | 4220 | `limit` không phải số nguyên từ 1 đến 100. |
| 422 | 4221 | `updated_since` không phải giây epoch. |
| 422 | 4222 | `cursor` không hợp lệ. |
| 429 | không có | Đã chạm rate limit. Body phẳng với `error_code` `rate_limited`, không phải envelope. |
| 503 | 5030 | Feed tạm thời không khả dụng. Retry với backoff. |
| 503 | 5031 | Wandura chưa kiểm được API key kịp thời. Key không sai: retry với backoff. |

Xem [Lỗi](https://docs.wandura.ai/vi/v1/developers/concepts/errors#creatives-errors) để biết cách xử lý từng trường hợp.
