> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Creatives API

> Create, update, list, and delete creatives (treatments) linked to offers and channels.

<Note>
  **See also**: [Creatives concept and configuration](/studio/creatives) for what this API powers, when to call it, and how it is configured.
</Note>

Creatives represent the content variant of an offer delivered through a specific channel. Each creative is linked to exactly one offer and one channel, and optionally to a placement within that channel.

All creatives support **soft-delete** (a `deletedAt` timestamp is set instead of permanent removal), **version tracking** (the `version` field auto-increments on every update), and **audit logging** (before/after snapshots are recorded for every CRUD operation).

<Info>
  See the [Creatives feature page](/studio/creatives) for UI guidance and conceptual overview.
</Info>

## Base path

```
/api/v1/creatives
```

***

## List creatives

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

Returns a paginated list of creatives for the current tenant, ordered by creation date (newest first). Each creative includes its parent offer, channel, and placement relations. By default, soft-deleted creatives are excluded.

### Query parameters

| Parameter        | Required | Type    | Description                                                       |
| ---------------- | -------- | ------- | ----------------------------------------------------------------- |
| `limit`          | No       | integer | Maximum results per page. Default `50`, max `100`.                |
| `cursor`         | No       | string  | Cursor for keyset pagination.                                     |
| `includeDeleted` | No       | string  | Set to `"true"` to include soft-deleted creatives in the results. |

### Response `200`

```json theme={null}
{
  "data": [
    {
      "id": "cre_abc123",
      "tenantId": "t_001",
      "name": "Platinum Card - Email Hero",
      "offerId": "off_001",
      "channelId": "ch_email",
      "placementId": "pl_email_hero",
      "contentItemId": null,
      "status": "active",
      "templateType": "email_html",
      "content": {
        "subject": "You're pre-approved for a higher limit",
        "headline": "Hey {first_name}, lift your limit to {recommended_credit_limit}",
        "body": "<p>Your Platinum status pre-qualifies you for a credit-limit increase...</p>",
        "ctaText": "Accept upgrade",
        "ctaUrl": "https://example.com/accept"
      },
      "personalization": [
        { "variable": "first_name", "fallback": "valued customer", "source": "customer.first_name" },
        { "variable": "recommended_credit_limit", "fallback": "$5,000", "source": "personalization.recommended_credit_limit" }
      ],
      "constraints": {
        "frequencyCapPerDay": 3,
        "cooldownHours": 24,
        "priorityOverride": 50
      },
      "abTestVariant": null,
      "weight": 100,
      "metrics": {},
      "version": 1,
      "deletedAt": null,
      "offer": { "id": "off_001", "name": "Platinum Card Upgrade" },
      "channel": { "id": "ch_email", "name": "Email" },
      "placement": null,
      "createdAt": "2026-03-10T12:00:00.000Z",
      "updatedAt": "2026-03-12T09:30:00.000Z"
    }
  ],
  "pagination": {
    "limit": 25,
    "cursor": null,
    "hasMore": false,
    "total": 18
  }
}
```

### Error codes

| Code  | Reason                                |
| ----- | ------------------------------------- |
| `401` | Missing or invalid API key / session. |
| `403` | Insufficient role.                    |

***

## Create a creative

```
POST /api/v1/creatives
```

Creates a new creative and triggers auto-assembly.

### Request body

| Field             | Required | Type            | Description                                                                                                                                                                                                                                                                                                                                                  |
| ----------------- | -------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`            | **Yes**  | string (1-255)  | Unique creative name.                                                                                                                                                                                                                                                                                                                                        |
| `offerId`         | **Yes**  | string          | Parent offer ID.                                                                                                                                                                                                                                                                                                                                             |
| `channelId`       | **Yes**  | string          | Target channel ID.                                                                                                                                                                                                                                                                                                                                           |
| `placementId`     | No       | string \| null  | Placement within the channel. When set, the creative becomes a candidate ONLY for that placement (per-(offer, placement) candidate expansion → Hungarian assignment). When `null`, it's a wildcard candidate across every placement on the channel. Default `null`.                                                                                          |
| `status`          | No       | enum            | `draft` (default), `active`, `paused`, `archived`.                                                                                                                                                                                                                                                                                                           |
| `templateType`    | No       | string          | Template format. Common values: `email_html`, `push_notification`, `sms_text`, `in_app_modal`, `banner`, `content_card`, `webhook_json`, `whatsapp_template`. Default `"email_html"`.                                                                                                                                                                        |
| `content`         | No       | object          | Template content. Typical fields: `subject`, `headline`, `body`, `imageUrl`, `ctaText`, `ctaUrl`, `deepLink`. Tokens like `{first_name}` are substituted at delivery time using the `personalization` mappings.                                                                                                                                              |
| `personalization` | No       | array           | Personalization token mappings — each entry is `{ variable, fallback, source }`. `variable` is the token name used in `content` (e.g. `first_name` for `{first_name}`); `source` is the data path (`customer.*`, `attributes.*`, `personalization.*` for computed values); `fallback` is rendered when the source resolves to null/undefined. Max 500 items. |
| `constraints`     | No       | object          | Delivery constraints. Typical fields: `frequencyCapPerDay` (integer), `cooldownHours` (integer), `priorityOverride` (0–100).                                                                                                                                                                                                                                 |
| `abTestVariant`   | No       | string \| null  | A/B test variant label (e.g. `"control"`, `"variant_a"`).                                                                                                                                                                                                                                                                                                    |
| `weight`          | No       | integer (0-100) | Traffic weight for multi-variant rotation. Default `100`.                                                                                                                                                                                                                                                                                                    |
| `metrics`         | No       | object          | Performance metric overrides.                                                                                                                                                                                                                                                                                                                                |

### Example request

```json theme={null}
{
  "name": "Platinum Card - Email Hero",
  "offerId": "off_001",
  "channelId": "ch_email",
  "placementId": "pl_email_hero",
  "templateType": "email_html",
  "content": {
    "subject": "You're pre-approved for a higher limit",
    "headline": "Hey {first_name}, lift your limit to {recommended_credit_limit}",
    "body": "<p>Your Platinum status pre-qualifies you for a credit-limit increase up to <strong>{recommended_credit_limit}</strong>.</p>",
    "ctaText": "Accept upgrade",
    "ctaUrl": "https://example.com/accept-platinum-upgrade"
  },
  "personalization": [
    { "variable": "first_name", "fallback": "valued customer", "source": "customer.first_name" },
    { "variable": "recommended_credit_limit", "fallback": "$5,000", "source": "personalization.recommended_credit_limit" }
  ],
  "constraints": {
    "frequencyCapPerDay": 3,
    "cooldownHours": 24,
    "priorityOverride": 50
  },
  "abTestVariant": "control",
  "weight": 100
}
```

### Response `201`

Returns the created creative with offer, channel, and placement relations, `version: 1`, and `deletedAt: null`. An audit log entry is created with a `create` action.

### Error codes

| Code  | Reason                                                                                                                                                                                                                                                     |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Validation error — missing `offerId`/`channelId`/`name`, or an `offerId`, `channelId`, or `placementId` that doesn't exist in your tenant (foreign-key ownership is validated, so a creative can't be linked to another tenant's offer/channel/placement). |
| `401` | Missing or invalid API key / session.                                                                                                                                                                                                                      |
| `403` | Insufficient role (requires `editor` or `admin`).                                                                                                                                                                                                          |
| `409` | A creative with that name already exists.                                                                                                                                                                                                                  |
| `413` | Request body exceeds the 2 MB limit.                                                                                                                                                                                                                       |
| `415` | `Content-Type` is not `application/json`.                                                                                                                                                                                                                  |

***

## Update a creative

```
PUT /api/v1/creatives
```

Updates an existing creative. Only provided fields are changed. The `version` field is auto-incremented and a before/after audit snapshot is recorded.

### Request body

All fields from the create schema are accepted as optional, plus:

| Field | Required | Type   | Description                |
| ----- | -------- | ------ | -------------------------- |
| `id`  | **Yes**  | string | The creative ID to update. |

### Example request

```json theme={null}
{
  "id": "cre_abc123",
  "status": "active",
  "weight": 80
}
```

### Response `200`

Returns the updated creative object with the incremented `version`.

### Error codes

| Code  | Reason                                     |
| ----- | ------------------------------------------ |
| `400` | Validation error.                          |
| `401` | Missing or invalid API key / session.      |
| `403` | Insufficient role.                         |
| `404` | No creative with that `id` in your tenant. |
| `409` | A creative with that name already exists.  |
| `413` | Request body exceeds the 2 MB limit.       |
| `415` | `Content-Type` is not `application/json`.  |

***

## Delete a creative (soft-delete)

```
DELETE /api/v1/creatives?id={creativeId}
```

Soft-deletes a creative by setting its `deletedAt` timestamp. The `version` is incremented. Creatives have no cascade children.

### Query parameters

| Parameter | Required | Type   | Description            |
| --------- | -------- | ------ | ---------------------- |
| `id`      | **Yes**  | string | Creative ID to delete. |

### Response `200`

```json theme={null}
{
  "success": true,
  "id": "cre_abc123"
}
```

### Error codes

| Code  | Reason                                                            |
| ----- | ----------------------------------------------------------------- |
| `400` | Missing `id` query parameter, or the creative is already deleted. |
| `401` | Missing or invalid API key / session.                             |
| `403` | Insufficient role.                                                |
| `404` | No creative with that `id` (or name) in your tenant.              |

<Note>
  To restore a soft-deleted creative, use `POST /api/v1/restore?entityType=creative&id={creativeId}` (admin only).
</Note>

***

## Role requirements

| Method | Minimum role |
| ------ | ------------ |
| GET    | `viewer`     |
| POST   | `editor`     |
| PUT    | `editor`     |
| DELETE | `editor`     |

<Card title="Creatives" icon="palette" href="/studio/creatives">
  Learn more about creating and managing creatives in the platform UI.
</Card>
