> ## Documentation Index
> Fetch the complete documentation index at: https://agenticadvertisingorg-feature-feedback.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Creative libraries and concepts

> Creative libraries in AdCP let buyers browse, organize, and track approval status for creatives across ad servers and management platforms.

Creative libraries let buyers manage creatives through AdCP — browsing existing assets, uploading new ones, assigning them to campaigns, and tracking approval status. A creative library is hosted by any agent that declares `has_creative_library: true` in its capabilities: ad servers (CM360, Flashtalking), creative management platforms (Celtra), or sales agents that also expose the Creative Protocol.

## The model

A creative library is an account-scoped collection of creative resources with stable `creative_id`s, observable lifecycle state, and assignment relationships that are separate from any one media buy or package. The implementation can be a full ad-server library or a thin view over seller storage, but the protocol commitment is the same: buyers can read the creative resource through `list_creatives`, update it through `sync_creatives`, and reference it by `creative_id` across assignments while the seller retains it.

Inline package creatives from a seller that does not advertise a creative library are not library creatives. They are package-scoped creative attachments: the seller accepts and serves them as part of the media buy, but does not advertise independent library management or cross-buy reuse.

A creative library organizes assets at three levels:

| Level    | AdCP equivalent                                                             | Examples                                                           |
| -------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Account  | Account (via [accounts protocol](/dist/docs/3.1.0-rc.13/accounts/overview)) | Advertiser in CM360, brand workspace in Celtra                     |
| Concept  | `concept_id` / `concept_name`                                               | Flashtalking concept, CM360 creative group, Celtra campaign folder |
| Creative | Creative item with `creative_id`, `format_id`, `assets`                     | A 300x250 display ad, a 30s video spot                             |

**Concepts** group related creatives across sizes and formats. A "Holiday 2026" concept might contain a 300x250 banner, a 728x90 leaderboard, and a 30s video — all expressing the same campaign idea. Use `concept_id` to filter and manage them as a group.

### Creative state and assignment state are separate

Two things the library tracks independently:

* **Creative state** — the review status of the creative itself: `processing`, `pending_review`, `approved`, `rejected`, or `archived`. Set by the creative agent's review workflow. Applies to the creative as a library asset, regardless of where it is used.
* **Assignment state** — the relationship between a creative and a package on a specific media buy. Created when the buyer assigns the creative (via `sync_creatives`, `creative_assignments`, or inline creatives on `create_media_buy`). Released when the media buy or package is rejected, canceled, or completed, or when the buyer removes the assignment.

These lifecycles are tracked independently:

* A creative in the library has **zero or more** active assignments at any time.
* Rejecting, canceling, or completing a media buy releases its assignments. It does not change the creative's review state, remove the creative from the library, or affect the creative's use in other media buys.
* When a creative's review state changes after assignments exist (e.g., a seller revokes an approval, or approves a previously rejected creative), sellers MAY continue or stop in-flight serving based on the new state. Buyers SHOULD re-fetch `approval_status` per package via [`get_media_buys`](/dist/docs/3.1.0-rc.13/media-buy/task-reference/get_media_buys) after a creative-state change to detect assignment-level impact. See [creative review](/dist/docs/3.1.0-rc.13/creative/sales-agent-creative-capabilities#creative-review).

Buyer agents reusing a library creative on a new media buy check **creative state** to know whether the asset is usable, and **assignment state** to know where it is currently in flight.

### Creatives outlast campaigns

A creative MUST persist in the library independently of the buys that reference it. Buy rejection, cancellation, or completion releases assignments only — the creative remains in the library at its current `status` and may be reused on subsequent buys. This holds regardless of how the creative entered the library: explicit [`sync_creatives`](/dist/docs/3.1.0-rc.13/creative/task-reference/sync_creatives), library-backed inline creative on [`create_media_buy`](/dist/docs/3.1.0-rc.13/media-buy/task-reference/create_media_buy), or platform-native upload exposed through AdCP. Sellers whose underlying ad server has no library object distinct from per-buy attachment satisfy this rule by exposing the buyer-synced creative through `list_creatives` for the buy's lifetime and continuing to expose its terminal state (including `archived`) after teardown — the library can be a thin view over per-buy storage; it does not need to be a separate store.

Retention beyond active assignments is seller-defined. An agent MAY archive an unassigned creative due to inactivity, post-flight expiry, or storage policy (see [creative status lifecycle](/dist/docs/3.1.0-rc.13/creative/specification#creative-status-lifecycle)), MAY transition `approved` → `suspended` for recoverable dependency loss such as a published-post authorization expiring, and MAY transition `approved` → `rejected` for policy revocation, takedown, or content drift. Whenever a creative's state changes after it has been synced by a buyer, the seller MUST make the new state observable so the buyer can resync, replace, or stop relying on the asset before reuse:

* For state changes affecting an active media buy (e.g., `approved` → `suspended` or `approved` → `rejected` on a creative with live assignments), sellers MUST surface a corresponding `impairment` on the buy. See [media buy health](/dist/docs/3.1.0-rc.13/media-buy/media-buys/lifecycle#health-and-dependency-impairment).
* For state changes on creatives with no active assignments (e.g., seller archives an unassigned creative for inactivity), sellers MUST reflect the new `status` on the next [`list_creatives`](/dist/docs/3.1.0-rc.13/creative/task-reference/list_creatives) read — that snapshot is the conformant signal today, per the [snapshot-and-log contract](/dist/docs/3.1.0-rc.13/protocol/snapshot-and-log). A push channel for account-scoped creative state changes is being defined under the [creative lifecycle webhooks RFC](https://github.com/adcontextprotocol/adcp/issues/2261); when that channel ships, sellers SHOULD additionally fire on it.

Buyers SHOULD confirm availability via [`list_creatives`](/dist/docs/3.1.0-rc.13/creative/task-reference/list_creatives) before reuse on a new buy. A library creative is the bundle of inputs the buyer supplied — uploaded assets, a brief, brand and catalog pointers, or any combination. Retention applies to the bundle; whether the format's rendered outputs are individually addressable is a format-level concern and is independent of library retention.

## Connecting to a library

Establish account access before querying:

```json theme={null}
{
  "accounts": [{
    "account_id": "acct_acme_2026",
    "account_name": "Acme Corp",
    "credentials": {
      "api_key": "..."
    }
  }]
}
```

The account setup is the same whether the library is on a standalone creative agent or a sales agent. See [accounts protocol](/dist/docs/3.1.0-rc.13/accounts/overview) for details.

## Browsing creatives

Use [`list_creatives`](/dist/docs/3.1.0-rc.13/creative/task-reference/list_creatives) to browse the library. Filter by concept, format, status, tags, or date range:

```json theme={null}
{
  "filters": {
    "concept_ids": ["concept_holiday_2026"],
    "statuses": ["approved"],
    "format_ids": [{
      "agent_url": "https://ads.flashtalking-example.com",
      "id": "display_300x250"
    }]
  },
  "include": {
    "variables": true,
    "assignments": true
  }
}
```

Each creative in the response includes:

```json theme={null}
{
  "creative_id": "ft_88201",
  "name": "Holiday 2026 - Medium Rectangle",
  "format_id": {
    "agent_url": "https://ads.flashtalking-example.com",
    "id": "display_300x250"
  },
  "status": "approved",
  "concept_id": "concept_holiday_2026",
  "concept_name": "Holiday 2026 Campaign",
  "created_date": "2026-10-15T14:00:00Z",
  "updated_date": "2026-11-20T09:30:00Z",
  "tags": ["holiday_2026", "display"],
  "variables": [
    {
      "variable_id": "headline",
      "name": "Headline text",
      "type": "text",
      "default_value": "Holiday Sale — Up to 40% Off"
    }
  ],
  "assignments": [
    { "package_id": "pkg_premium_display", "weight": 100 }
  ]
}
```

The `status` field reflects the creative's current state in the library: `processing`, `pending_review`, `approved`, `rejected`, or `archived`. See [creative review](/dist/docs/3.1.0-rc.13/creative/sales-agent-creative-capabilities#creative-review) for how status transitions work.

## Uploading creatives

Use [`sync_creatives`](/dist/docs/3.1.0-rc.13/creative/task-reference/sync_creatives) to upload new creatives or update existing ones. The operation uses upsert semantics — if a `creative_id` already exists, it updates; otherwise it creates.

```json theme={null}
{
  "creatives": [
    {
      "creative_id": "acme_video_001",
      "name": "Holiday Sale 30s",
      "format_id": {
        "agent_url": "https://creative.adcontextprotocol.org",
        "id": "video_standard_30s"
      },
      "assets": {
        "video": {
          "url": "https://cdn.acme-example.com/holiday-sale-30s.mp4",
          "width": 1920,
          "height": 1080,
          "duration_ms": 30000
        },
        "click_url": {
          "url": "https://acme-example.com/holiday-sale"
        }
      }
    }
  ]
}
```

The response tells you what happened to each creative:

```json theme={null}
{
  "creatives": [
    {
      "creative_id": "acme_video_001",
      "action": "created"
    }
  ]
}
```

After upload, the creative enters the library's review process. Check `list_creatives` to see when it transitions from `pending_review` to `approved`.

### Uploading with assignments

Assign creatives to packages in the same call:

```json theme={null}
{
  "creatives": [
    {
      "creative_id": "acme_video_001",
      "name": "Holiday Sale 30s",
      "format_id": { "agent_url": "...", "id": "video_standard_30s" },
      "assets": { "...": "..." }
    }
  ],
  "assignments": [
    {
      "creative_id": "acme_video_001",
      "package_id": "pkg_premium_video"
    }
  ]
}
```

## Generating tags from library creatives

When you need a serving tag for a creative in the library, use [`build_creative`](/dist/docs/3.1.0-rc.13/creative/task-reference/build_creative) with `creative_id` instead of a manifest:

```json theme={null}
{
  "creative_id": "ft_88201",
  "concept_id": "concept_holiday_2026",
  "target_format_id": {
    "agent_url": "https://ads.flashtalking-example.com",
    "id": "display_300x250"
  }
}
```

The creative agent resolves the `creative_id` from its library and returns a manifest with the serving tag. The tag format depends on the platform:

* **Flashtalking, Celtra**: Universal tags that adapt to any environment. No placement context needed.
* **CM360**: Placement-level tags that require trafficking context. Pass `media_buy_id` and `package_id`:

```json theme={null}
{
  "creative_id": "cm360_creative_12345",
  "target_format_id": {
    "agent_url": "https://ads.cm360-example.com",
    "id": "display_300x250"
  },
  "media_buy_id": "buy_holiday_q4",
  "package_id": "pkg_premium_display"
}
```

See [tag generation models](/dist/docs/3.1.0-rc.13/creative/implementing-creative-agents#tag-generation-models) for the full breakdown.

## Assigning creatives to campaigns

There are two paths for attaching library creatives to a media buy:

### Path 1: Creative assignments on the package

Reference library creatives by ID when creating the media buy:

```json theme={null}
{
  "packages": [{
    "product_id": "premium_display",
    "creative_assignments": [
      { "creative_id": "ft_88201", "weight": 60 },
      { "creative_id": "ft_88202", "weight": 40 }
    ]
  }]
}
```

This works when the creative is already in the agent's library (via `sync_creatives` or the platform's own upload flow).

### Path 2: Inline creatives on the package

Upload the creative directly with the media buy — no separate sync step:

```json theme={null}
{
  "packages": [{
    "product_id": "premium_display",
    "creatives": [{
      "creative_id": "acme_banner_001",
      "name": "Holiday banner",
      "format_id": { "agent_url": "...", "id": "display_300x250" },
      "assets": { "...": "..." }
    }]
  }]
}
```

For sellers that also advertise `creative.has_creative_library: true`, the agent adds the creative to its library and assigns it to the package in one operation. For inline-only sellers that do not advertise a creative library, the same `creatives` payload assigns package-scoped assets without creating a reusable library entry. See [inline creative management](/dist/docs/3.1.0-rc.13/creative/sales-agent-creative-capabilities) for details.

**Library-backed inline creatives follow the same library lifecycle as `sync_creatives` uploads.** When the seller advertises `creative.has_creative_library: true`, the inline form is a convenience — "sync and assign in one call" — not a separate lifecycle. Once submitted, the creative enters the library with the same review flow, retention, and identifiers it would have under `sync_creatives`. If the `create_media_buy` task resolves as `pending_manual` and the buy never activates, or if the buy is rejected or canceled, only the package assignments are released; the creatives remain in the library and may be referenced by `creative_id` in a subsequent `create_media_buy` call. This assignment-release behavior is normative on the media-buy side — see the [Media Buy State Transitions](/dist/docs/3.1.0-rc.13/media-buy/specification#media-buy-state-transitions) rule.

For inline-only sellers, buyers should treat the creative body as attached to the media-buy package. The seller may retain enough package-scoped creative state to review, serve, replace, and audit the buy, but it has not advertised reusable library operations such as `list_creatives`, `sync_creatives`, or later `creative_assignments` reuse.

Creative review proceeds independently of the media buy outcome. Sellers MUST NOT skip review solely because the buy did not activate, and a buy rejection does not by itself imply rejection of the submitted creatives — a creative rejection MUST be a deliberate review decision with its own `rejection_reason`, not implicit from the containing buy's status. Sellers MAY deprioritize review of creatives that currently have no active assignments, provided review completes before any future assignment activates.

**Capability-flag scope.** `inline_creative_management: true` advertises that the sales agent accepts inline creatives on `create_media_buy` and `update_media_buy`; it does not by itself advertise a creative library. The decoupled library lifecycle applies when the seller also advertises `creative.has_creative_library: true`.

### Multi-seller distribution

When you work with multiple sellers, build creatives once and distribute them:

1. **Build** on your creative agent:

```json theme={null}
{
  "message": "Create a holiday promotion banner",
  "target_format_ids": [
    { "agent_url": "https://creative.adcontextprotocol.org", "id": "display_300x250" },
    { "agent_url": "https://creative.adcontextprotocol.org", "id": "display_728x90" }
  ]
}
```

2. **Sync** to each seller's library:

```json theme={null}
{
  "creatives": [
    {
      "creative_id": "holiday_2026_300x250",
      "name": "Holiday 2026 - Medium Rectangle",
      "concept_id": "concept_holiday_2026",
      "format_id": { "agent_url": "https://creative.adcontextprotocol.org", "id": "display_300x250" },
      "assets": { }
    }
  ]
}
```

Call `sync_creatives` on each sales agent separately. Use the same `creative_id` and `concept_id` across sellers so you can correlate the same creative and campaign concept across your media buys. See [Multi-agent creative orchestration](/dist/docs/3.1.0-rc.13/creative/multi-agent-orchestration) for the full pattern.

3. **Track approval** per seller — each seller reviews independently. Poll `list_creatives` on each agent to check status. A creative may be `approved` on one seller and `rejected` on another based on their policies.

## Tracking approval status

Creative approval operates at two levels:

**Library level**: The `status` field on each creative in [`list_creatives`](/dist/docs/3.1.0-rc.13/creative/task-reference/list_creatives) — `processing`, `pending_review`, `approved`, `rejected`, or `archived`.

**Package level**: The `approval_status` on each creative in [`get_media_buys`](/dist/docs/3.1.0-rc.13/media-buy/task-reference/get_media_buys) — `pending_review`, `approved`, or `rejected` with `rejection_reason`.

A creative can be `approved` in the library but `rejected` at the package level if it violates placement-specific policies. Poll both after syncing or submitting a media buy with new creatives.

## Dynamic creative optimization (DCO)

Creatives with dynamic content variables appear in the library with a `variables` array when you request `include: { variables: true }`. Each variable defines a slot that the ad server fills at serve time:

```json theme={null}
{
  "variables": [
    {
      "variable_id": "headline",
      "name": "Headline text",
      "type": "text",
      "default_value": "Holiday Sale — Up to 40% Off"
    },
    {
      "variable_id": "product_image",
      "name": "Product image",
      "type": "image",
      "default_value": "https://cdn.acme-example.com/hero.jpg"
    },
    {
      "variable_id": "cta_color",
      "name": "CTA button color",
      "type": "color",
      "default_value": "#FF6600"
    }
  ]
}
```

Use `has_variables: true` in `list_creatives` filters to find DCO creatives. Variable types match common platform patterns: `text`, `color`, `image`, `video`, `number`, `boolean`.

How the ad server uses these variables at serve time (data feeds, targeting rules, optimization algorithms) is outside AdCP's scope. AdCP models the variable *slots*, not the optimization logic.

## Next steps

* [Generative creative](/dist/docs/3.1.0-rc.13/creative/generative-creative) — AI-powered creative generation and brief-in-media-buy workflows
* [Creative capabilities on sales agents](/dist/docs/3.1.0-rc.13/creative/sales-agent-creative-capabilities) — When the seller manages both media and creative
* [Implementing creative agents](/dist/docs/3.1.0-rc.13/creative/implementing-creative-agents) — Building an AdCP creative agent around your platform
* [sync\_creatives reference](/dist/docs/3.1.0-rc.13/creative/task-reference/sync_creatives) — Upload API details
* [list\_creatives reference](/dist/docs/3.1.0-rc.13/creative/task-reference/list_creatives) — Query API details with full filtering options
