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

# Implementing Creative Agents

> How to build an AdCP creative agent that defines formats, validates manifests, generates previews, and hosts a creative library.

> **Canonical formats in 3.2**: creative agents declare build, validation, and preview capabilities through `creative.supported_formats` on `get_adcp_capabilities`. `list_creative_formats` and named format IDs are deprecated compatibility surfaces. See [canonical formats](/dist/docs/3.2.0-beta.0/creative/canonical-formats).

This guide explains how to implement a creative agent that advertises and executes canonical creative operations.

## What is a creative agent?

A creative agent is a service that:

* **Declares capabilities** - Publishes the canonical contracts it can build, validate, or preview
* **Validates manifests** - Ensures creative manifests meet format requirements
* **Generates previews** - Shows how creatives will render
* **Builds creatives** (optional) - Generates manifests from natural language briefs or retrieves them from a library
* **Hosts a creative library** (optional) - Lets buyers browse and filter existing creatives

An ad server (CM360, Flashtalking), creative management platform, creative agency, publisher, or sales agent can implement a creative agent. Sales agents that implement the Creative Protocol alongside the Media Buy Protocol serve both roles from a single endpoint — see [Creative capabilities on sales agents](/dist/docs/3.2.0-beta.0/creative/sales-agent-creative-capabilities).

## Three interaction models

Creative agents fall into three distinct categories based on how assets arrive and what the output is. Identifying which model your agent follows determines which tasks to implement and how buyers will interact with you.

### Stateless: template and transformation agents

**Examples:** Celtra, format conversion services, rich media template platforms

The buyer passes all assets inline with each call. Your agent applies a template or transformation and returns the result. There is no persistent creative library — every call is self-contained.

| Task                    | Role                                                                  |
| ----------------------- | --------------------------------------------------------------------- |
| `get_adcp_capabilities` | Publish canonical supported formats and operations                    |
| `list_transformers`     | Discover account-scoped templates, models, configuration, and pricing |
| `preview_creative`      | Render a template with provided assets                                |
| `build_creative`        | Transform input assets into a serving tag                             |

**Capabilities:** `supports_transformation: true`

The buyer's workflow: discover your formats → preview with real assets → request built creatives for trafficking.

### Stateful (pre-loaded): ad servers

**Examples:** Innovid, Flashtalking, CM360

Creatives already exist in your system, loaded through your platform's UI or API. Buyers connect to browse your library and request serving tags for their media buys. The buyer never pushes assets to you — they reference creatives that are already there.

| Task                    | Role                                                              |
| ----------------------- | ----------------------------------------------------------------- |
| `list_creatives`        | Browse existing creatives in the library                          |
| `build_creative`        | Generate a serving tag for a specific `creative_id` and media buy |
| `preview_creative`      | Preview an existing creative                                      |
| `get_creative_delivery` | Report variant-level delivery metrics                             |

**Capabilities:** `has_creative_library: true`

The buyer's workflow: browse your creative library → request tags per media buy → track delivery.

### Stateful (push): sales agents with creative

**Examples:** Publisher platforms, retail media networks, native ad platforms

Buyers push creative assets or catalog items to your platform. You validate, store, and render them in your environment. This is where catalog-driven creative gets interesting — buyers might push product feeds, flight listings, or hotel inventory that you render as native ads.

| Task                    | Role                                                          |
| ----------------------- | ------------------------------------------------------------- |
| `get_products`          | Publish the closed canonical format set on each sales product |
| `sync_creatives`        | Accept pushed assets or catalog items                         |
| `preview_creative`      | Preview pushed creatives in your platform's environment       |
| `get_creative_delivery` | Report delivery metrics                                       |

**Capabilities:** `has_creative_library: true`

The buyer's workflow: discover your accepted formats → push assets → preview in your environment.

### Choosing your model

The key question is: **where do the assets come from?**

* If the buyer sends assets with every call → **stateless (template/transformer)**
* If creatives already exist in your system → **stateful (ad server)**
* If the buyer pushes assets to you for hosting → **stateful (sales agent)**

Some agents combine models. A creative management platform might be both a template engine (stateless transformation) and a library host (stateful). Declare the appropriate capability flags in `get_adcp_capabilities` so buyers can determine the right interaction model.

### Pricing and statefulness

A creative agent that charges for its services needs an account relationship. Adding pricing requires:

1. **Implement the [Accounts Protocol](/dist/docs/3.2.0-beta.0/accounts/overview)** — buyers establish accounts with rate cards
2. **Expose `pricing_options` on discovery** — on `list_transformers` (transformation/generation agents) or `list_creatives` (ad servers/library agents)
3. **Return pricing in `build_creative` responses** — `pricing_option_id`, `vendor_cost`, `currency`, and `consumption`
4. **Accept `report_usage`** — orchestrators report what was served so you can track revenue

Free transformation agents remain stateless and unchanged. No account, no pricing required.

#### Pricing discovery by agent type

| Agent type                     | Discovery surface   | Why                                                                       |
| ------------------------------ | ------------------- | ------------------------------------------------------------------------- |
| **Transformation**             | `list_transformers` | Buyers see pricing per canonical output capability before a build         |
| **Generation**                 | `list_transformers` | Pricing is attached to an account-scoped build offering                   |
| **Ad server** (Innovid, CM360) | `list_creatives`    | Buyers see pricing on specific creatives in the library                   |
| **Both**                       | Both surfaces       | Library pricing on `list_creatives`, build pricing on `list_transformers` |

Transformation and generation agents do not need to implement `list_creatives` for pricing. Their product-like, account-scoped offering is the transformer; the canonical format capability remains stable in `get_adcp_capabilities`.

#### Pricing walkthrough

Here is the full round-trip for a transformation agent charging per format adapted.

**Step 1: Buyer discovers pricing via `list_transformers`**

The buyer calls `list_transformers` with `include_pricing: true` and their account. Your agent returns `pricing_options` and canonical `output_capability_ids` on each transformer.

```json theme={null}
{
  "transformers": [
    {
      "transformer_id": "display_adapter",
      "name": "Display adapter",
      "output_capability_ids": ["display_image_300x250"],
      "pricing_options": [
        {
          "pricing_option_id": "po_standard_per_format",
          "model": "per_unit",
          "unit": "format",
          "unit_price": 2.00,
          "currency": "USD"
        },
        {
          "pricing_option_id": "po_volume_per_format",
          "model": "per_unit",
          "unit": "format",
          "unit_price": 1.25,
          "currency": "USD"
        }
      ]
    }
  ]
}
```

Multiple options are common — here the buyer sees a standard rate and a volume rate. For ad servers, the same `pricing_options` pattern appears on `list_creatives` instead.

**Step 2: Buyer builds a creative**

The buyer calls `build_creative` with their `account`. Your agent performs the work, selects the applicable pricing option server-side (based on the account's commitment level, the work performed, etc.), and returns the cost:

```json theme={null}
{
  "creative_manifest": {
    "creative_id": "cr_hero_banner",
    "format_kind": "image",
    "assets": { "..." : "..." }
  },
  "pricing_option_id": "po_standard_per_format",
  "vendor_cost": 2.00,
  "currency": "USD",
  "consumption": {
    "renders": 1
  }
}
```

The `pricing_option_id` tells the buyer which rate was applied. The `consumption` object lets the buyer verify: 1 render × $2.00/format = $2.00 `vendor_cost`.

For **CPM-priced creatives** (ad servers), `vendor_cost` is 0 at build time — cost accrues when impressions are served:

```json theme={null}
{
  "creative_manifest": { "..." : "..." },
  "pricing_option_id": "po_video_cpm",
  "vendor_cost": 0,
  "currency": "USD"
}
```

**Step 3: Buyer reports usage**

After the campaign delivers, the buyer reports usage via [`report_usage`](/dist/docs/3.2.0-beta.0/accounts/tasks/report_usage). This example shows CPM reporting, where cost accrued during delivery rather than at build time. The `pricing_option_id` and `creative_id` flow through for reconciliation:

```json theme={null}
{
  "reporting_period": { "start": "2026-03-01T00:00:00Z", "end": "2026-03-31T23:59:59Z" },
  "usage": [
    {
      "account": { "account_id": "acct_acme_creative" },
      "creative_id": "cr_hero_banner",
      "pricing_option_id": "po_video_cpm",
      "impressions": 2400000,
      "vendor_cost": 1200.00,
      "currency": "USD"
    }
  ]
}
```

Your agent validates that `pricing_option_id` matches the account's rate card and accepts the record.

#### Who selects the pricing option?

The **vendor agent** selects the pricing option, not the buyer. The buyer passes `account` on `build_creative` — the agent determines which pricing option applies based on the account's rate card, the work performed, and any commitment tiers. The response tells the buyer what was applied.

The buyer does not pass `pricing_option_id` on the `build_creative` request. They see the options on `list_creatives`, and they receive the applied option on the `build_creative` response.

#### Consumption fields by agent type

| Agent type      | Typical `consumption` fields | Notes                                      |
| --------------- | ---------------------------- | ------------------------------------------ |
| Transformation  | `renders`                    | Number of format adaptations performed     |
| AI generation   | `tokens`, `images_generated` | LLM tokens consumed, images produced       |
| Ad server (CPM) | Omitted                      | Cost accrues at serve time, not build time |
| Multi-variant   | `renders`                    | Number of variants rendered                |

The `consumption` object is informational — it lets the buyer verify that `vendor_cost` is consistent with the rate card. `vendor_cost` is the billing source of truth.

## Core requirements

### 1. Canonical capability identity

Every supported-format entry uses a stable agent-local `capability_id` for task routing and a full canonical declaration for compatibility matching:

```json theme={null}
{
  "capability_id": "vertical_story_video",
  "operations": ["build", "validate", "preview"],
  "format": {
    "format_kind": "video_hosted",
    "params": {
      "aspect_ratio": "9:16",
      "duration_ms_range": [3000, 15000]
    }
  }
}
```

Keep capability IDs stable and unique within your agent's `supported_formats[]` catalog. They are scoped to your agent and passed as `target_capability_id`; they are not format identities and never appear on products or manifests.

### 2. Format validation

Your capability declaration is authoritative for what your creative agent can do. Publisher acceptance and sales-agent deliverability remain authoritative on their own catalog/product surfaces.

**Format definition example:**

```json theme={null}
{
  "capability_id": "story_sequence_5frame",
  "operations": ["build", "preview"],
  "format": {
    "format_kind": "image_carousel",
    "params": {
      "cards_min": 5,
      "cards_max": 5,
      "width": 1080,
      "height": 1920
    }
  }
}
```

## Required tasks

Creative agents must implement capability discovery and every operation they advertise.

### get\_adcp\_capabilities

Return canonical `creative.supported_formats[]` entries.

**Key responsibilities:**

* Stable `capability_id`
* Complete canonical `format` declaration
* Accurate build, validate, and preview `operations`
* `{publisher_domain, format_option_id}` for exact publisher-format support

See [`get_adcp_capabilities`](/dist/docs/3.2.0-beta.0/protocol/get_adcp_capabilities).

### preview\_creative

Generate a visual preview showing how a creative manifest will render in your format.

**Key responsibilities:**

* Validate manifest against format requirements
* Return validation errors if manifest is invalid
* Generate visual representation (URL, image, or HTML)
* Preview should be accessible for at least 24 hours

See [preview\_creative task reference](/dist/docs/3.2.0-beta.0/creative/task-reference/preview_creative) for complete API specification.

## Optional tasks

### build\_creative

Generate a creative manifest from a natural language brief, transform an existing manifest to a new format, or retrieve a library creative as a delivery-ready manifest.

**Key responsibilities:**

* Parse natural language brief or resolve a `creative_id` from your library
* Generate or source appropriate assets
* Return valid manifest for the target format
* Substitute `macro_values` into serving tags when provided
* Optionally return preview URL

See [build\_creative task reference](/dist/docs/3.2.0-beta.0/creative/task-reference/build_creative) for complete API specification.

### list\_creatives

Browse and filter creatives in your library. Implement this if your platform hosts a creative library that buyers need to query.

**Key responsibilities:**

* Return creatives accessible to the authenticated account
* Support filtering by format, status, tags, and date range
* Support pagination for large libraries
* Optionally include dynamic creative optimization (DCO) variable definitions per creative

See [list\_creatives task reference](/dist/docs/3.2.0-beta.0/creative/task-reference/list_creatives) for complete API specification.

### sync\_creatives

Accept creative asset uploads into your library. Implement this if your platform allows buyers to push assets.

**Key responsibilities:**

* Validate creatives against format specifications
* Return per-creative results with platform-assigned IDs
* Support upsert semantics (create or update by `creative_id`)
* Optionally support bulk package assignments (for agents that also manage media buys)
* Optionally support async approval workflows for brand safety review

See [sync\_creatives task reference](/dist/docs/3.2.0-beta.0/creative/task-reference/sync_creatives) for complete API specification.

## Integration with the Media Buy Protocol

`sync_creatives` appears in both the Creative Protocol and the Media Buy Protocol, which is a common source of confusion. It is one task with one schema; what changes is the role of the agent receiving it:

* **Sales agents** (Media Buy Protocol) accept `sync_creatives` to traffic creatives: upload into the seller's library, assign to packages in media buys, and run the seller's review pipeline. This is the call a buyer makes when activating a campaign.
* **Creative agents** (this guide) MAY accept `sync_creatives` as an optional library on-ramp: buyers push assets into your library so `build_creative` and `list_creatives` can reference them later. No packages or media buys are involved unless your platform also manages them.

A typical buyer flow uses both endpoints in sequence:

1. **Build**: the buyer calls your `build_creative` (or assembles a manifest by hand) and checks the result with `preview_creative`.
2. **Traffic**: the buyer sends the finished manifest to the sales agent's `sync_creatives`, with package assignments for the media buy.
3. **Deliver**: the sales agent validates the manifest against its product's canonical format declaration and serves the creative.

Your creative agent is not in the path of step 2; buyers call the sales agent directly. Compatibility is established by comparing your `creative.supported_formats[]` declaration with the product's `format_options[]`, not by making either agent authoritative for the other's catalog.

## Validation best practices

### Manifest validation

When validating manifests:

1. **Check canonical contract** - Resolve `format_kind` and any `format_option_ref`, then validate against the selected capability/product declaration
2. **Validate required assets** - All required assets must be present
3. **Check asset types** - Assets must match specified types
4. **Validate requirements** - Dimensions, file types, sizes, etc.
5. **URL accessibility** - Verify asset URLs are accessible (optional but recommended)

**Example validation errors:**

```json theme={null}
{
  "status": "error",
  "error": "validation_failed",
  "validation_errors": [
    {
      "asset_id": "frame_1_image",
      "error": "missing_required_asset",
      "message": "Required asset 'frame_1_image' is missing"
    },
    {
      "asset_id": "brand_logo",
      "error": "invalid_dimensions",
      "message": "Logo must be 200x200px, got 150x150px"
    }
  ]
}
```

### Disclosure requirements

When a creative brief includes `compliance.required_disclosures`, creative agents must ensure each disclosure appears in the generated creative. The workflow:

1. **Check format support** — Compare each `required_disclosures[].position` against the format's `supported_disclosure_positions` or `disclosure_capabilities`. If a required position is not supported by the format, return a validation error rather than silently dropping it. When `disclosure_capabilities` is present, use it for persistence-aware matching — verify that the format supports both the required position and the required persistence mode.

2. **Respect persistence** — When the brief specifies `persistence` on a required disclosure, the creative agent must satisfy it using a position that supports that persistence mode in the format's `disclosure_capabilities`. For example, if a brief requires `"continuous"` persistence for an EU AI Act disclosure, the format must declare that position with `"continuous"` in its `disclosure_capabilities`. When the brief omits `persistence`, use the most restrictive persistence mode the format supports for that position.

3. **Render disclosures** — For positions your format supports:
   * `footer`, `overlay`, `end_card`, `prominent`: Render the disclosure `text` into the creative at the specified position
   * `audio`, `pre_roll`: Include disclosure as spoken audio. Respect `min_duration_ms` if specified.
   * `subtitle`: Include as a text track within the video creative
   * `companion`: Deliver in the companion ad unit alongside the primary creative

4. **Respect jurisdiction scoping** — A disclosure with `jurisdictions: ["US"]` is legally required only in the US. Creative agents that produce a single creative per brief should include all jurisdictional disclosures. If your agent can produce jurisdiction-specific variants, filter disclosures by their `jurisdictions` field.

5. **Propagate into provenance** — When the brief specifies `persistence` and `position` on a required disclosure, propagate these into `provenance.disclosure.jurisdictions[].render_guidance` on the creative manifest. The brief is a creation-time document; at serve time, the publisher has the creative and its provenance, not the brief. If the creative agent does not propagate persistence into provenance render guidance, the publisher has no way to know what persistence the regulation requires.

6. **Preserve through regeneration** — When regenerating or resizing a creative, carry forward all disclosures from the `BriefAsset` attached to the manifest. A `BriefAsset` is a `brief`-typed asset in the format's `assets` array that carries the creative brief through the manifest, ensuring disclosures survive format adaptation.

**Example:** A brief requires `"KI-generiert"` disclosure at `overlay` position with `persistence: "continuous"` for `eu_ai_act_article_50`. Your format declares `disclosure_capabilities: [{ "position": "overlay", "persistence": ["continuous", "initial"] }]`. The format supports continuous overlay, so the creative agent renders the disclosure as a persistent overlay visible throughout the content. The agent also propagates `render_guidance: { "persistence": "continuous", "positions": ["overlay"] }` into the EU jurisdiction entry in `provenance.disclosure.jurisdictions[]`.

### Format evolution

When updating format definitions:

* **Additive changes** (new optional assets with `required: false` in `assets`) are safe
* **Breaking changes** (removing slots or tightening requirements) require a new `capability_id` or a versioned publisher `format_option_id`
* Maintain backward compatibility when possible

## Deployment checklist

Before launching your creative agent:

* [ ] MCP and/or A2A endpoints are accessible
* [ ] `get_adcp_capabilities` returns `creative.supported_formats` with at least one entry
* [ ] Every supported format has a stable `capability_id`
* [ ] Every capability carries a canonical `format_kind` and honest parameter envelope
* [ ] Exact publisher-format claims include `{publisher_domain, format_option_id}`
* [ ] `preview_creative` validates manifests and generates previews
* [ ] Format definitions include complete asset requirements
* [ ] Documentation available for your custom formats

To verify a remote creative agent is reachable and advertising its format surface, call `get_adcp_capabilities` on the agent endpoint and confirm that the response includes a non-empty `creative.supported_formats` array. Each entry follows the [canonical format declaration](/dist/docs/3.2.0-beta.0/creative/canonical-formats) shape.

<Accordion title="Verify an MCP creative agent">
  ```bash theme={null}
  export AGENT_URL="https://your-creative-agent.example.com/mcp"

  # 1. Initialize MCP and capture Mcp-Session-Id when the server is stateful.
  SESSION_ID=$(curl -s -D - -o /dev/null -X POST "$AGENT_URL" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "initialize",
      "params": {
        "protocolVersion": "2024-11-05",
        "capabilities": {},
        "clientInfo": { "name": "adcp-probe", "version": "1.0" }
      }
    }' | grep -i '^mcp-session-id:' | awk '{print $2}' | tr -d '\r\n')

  HEADERS=(-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream")
  [ -n "$SESSION_ID" ] && HEADERS+=(-H "Mcp-Session-Id: $SESSION_ID")

  # 2. Complete the MCP initialization lifecycle before calling a tool.
  curl -s -o /dev/null -X POST "$AGENT_URL" "${HEADERS[@]}" \
    -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'

  # 3. Call get_adcp_capabilities with the same session header.
  curl -X POST "$AGENT_URL" "${HEADERS[@]}" \
    -d '{
      "jsonrpc": "2.0",
      "id": 2,
      "method": "tools/call",
      "params": {
        "name": "get_adcp_capabilities",
        "arguments": {
          "adcp_version": "3.2",
          "adcp_major_version": 3,
          "protocols": ["creative"]
        }
      }
    }'
  ```

  Read the AdCP payload from the MCP result and verify that it contains a creative capability block like this:

  ```json theme={null}
  {
    "creative": {
      "supported_formats": [
        {
          "capability_id": "display_banner",
          "operations": ["build", "validate", "preview"],
          "format": {
            "format_kind": "image",
            "params": {
              "width": 300,
              "height": 250
            }
          }
        }
      ]
    }
  }
  ```

  An unreachable endpoint, an authorization error, a missing `creative` block, or an empty `supported_formats` array means the agent is not ready for creative-format discovery. If the endpoint requires authentication, include the credential configured for that agent.
</Accordion>

## Integration patterns

### Pattern 1: creative agency

You're a creative agency building custom formats for brands:

```json theme={null}
{
  "capability_id": "hero_video_package",
  "operations": ["build", "preview"],
  "format": {
    "format_kind": "video_hosted",
    "params": { "sizes": [{"w": 1920, "h": 1080}, {"w": 1080, "h": 1920}, {"w": 1080, "h": 1080}] }
  }
}
```

### Pattern 2: platform-specific formats

You're a platform defining specialized formats:

```json theme={null}
{
  "capability_id": "interactive_quiz",
  "operations": ["build", "preview"],
  "format": {
    "format_kind": "custom",
    "format_shape": "interactive_experience",
    "format_schema": { "uri": "https://creative.example/quiz-schema.json", "digest": "sha256:..." },
    "params": {}
  }
}
```

### Pattern 3: format extension service

You provide enhanced versions of standard formats:

```json theme={null}
{
  "capability_id": "video_30s_optimized",
  "operations": ["build", "validate"],
  "format": {
    "format_kind": "video_hosted",
    "params": { "duration_ms_exact": 30000, "containers": ["mp4", "webm"] }
  }
}
```

### Pattern 4: feed-native/social format agent

You host ad formats that render as native content within your platform's feed:

```json theme={null}
{
  "capability_id": "promoted_post",
  "operations": ["build", "preview"],
  "format": {
    "publisher_domain": "social.streamhaus.example",
    "format_option_id": "promoted_post",
    "format_kind": "native_in_feed",
    "params": {
      "headline_max_chars": 300,
      "body_max_chars": 1000,
      "image_width": 1200,
      "image_height": 628
    }
  }
}
```

Platform-specific rendering (dark mode, community context, engagement UI) is handled by the agent at preview and serve time — the format definition specifies only the buyer-provided assets. The agent wraps these assets in the platform's native chrome.

When a buyer calls `preview_creative` for a feed-native format, the preview renders the buyer's assets inside the platform's UI — avatar, engagement buttons, community badge, and all:

```json theme={null}
{
  "request_type": "single",
  "creative_manifest": {
    "format_kind": "native_in_feed",
    "format_option_ref": {
      "scope": "publisher",
      "publisher_domain": "social.streamhaus.example",
      "format_option_id": "promoted_post"
    },
    "assets": {
      "headline": { "content": "Introducing our new trail running collection" },
      "body": { "content": "Built for the mountains. Tested on every terrain." },
      "image": { "url": "https://cdn.acme-example.com/trail-hero.jpg", "width": 1200, "height": 628 },
      "click_url": { "url": "https://acme-example.com/trail-running" }
    }
  },
  "inputs": [
    { "name": "Running community", "context_description": "Appears in r/trailrunning feed between user posts" },
    { "name": "General feed", "context_description": "Appears in home feed between mixed content" }
  ]
}
```

The preview response shows how the ad looks in each context — including community-specific chrome that the buyer cannot preview elsewhere. This is why platforms should implement `preview_creative` even for simple formats: the platform chrome is the differentiator.

## Platform mapping

If you're wrapping an existing ad server or creative management platform, this section shows how common platform concepts map to the creative protocol.

### Concept mapping

| Platform concept                           | AdCP equivalent                                                              | Notes                                                                                                                 |
| ------------------------------------------ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Advertiser / account                       | Account (via [accounts protocol](/dist/docs/3.2.0-beta.0/accounts/overview)) | Buyer establishes access before querying the library                                                                  |
| Creative concept / group / template folder | `concept_id` in `list_creatives`                                             | Groups related creatives across sizes/formats (Flashtalking concepts, Celtra campaign folders, CM360 creative groups) |
| Creative                                   | Creative item in `list_creatives` response                                   |                                                                                                                       |
| Creative type + constraints                | Canonical `format_kind` + declaration `params`                               | Type and constraint identity are separate and machine-comparable                                                      |
| Template                                   | Transformer + canonical output capability                                    | Transformer carries account-scoped configuration; capability carries the stable format contract                       |
| Template object properties (Celtra)        | `variables` array                                                            | Named slots with types (text, color, image, video, number, boolean) — near-exact match                                |
| Active / archived / pending                | `status` field                                                               |                                                                                                                       |
| Ad tag / serving tag                       | Asset in a creative manifest (`html`, `javascript`, or `vast` type)          | Tags are just assets — no special concept                                                                             |
| Placement / ad unit                        | Package within a media buy                                                   | The buy context where a creative is assigned                                                                          |
| DCO variables / dynamic fields             | `variables` array (via `include_variables=true`)                             | Named slots with types and defaults                                                                                   |
| Data feed / targeting rules                | Not modeled                                                                  | AdCP models the variable *slots*, not the optimization rules                                                          |
| CTV/OTT ad server (Innovid, Brightcove)    | Same as ad server, plus VAST/SSAI delivery model                             | VAST tags in `vast`-type assets; companion ads via multi-render formats                                               |

### Tag generation models

Ad servers differ in how they produce serving tags. `build_creative` accommodates the models through `creative_id`, canonical `target_capability_id`, and optional `media_buy_id`/`package_id`:

**Universal tags** — A single tag adapts to multiple environments. No placement context is needed; choose the agent's universal-tag capability.

**Single-placement tags** — The chosen capability declaration fixes the relevant constraints and the caller supplies placement context when needed.

**Multi-placement tags** — The chosen capability declares a multi-size canonical envelope.

**Placement-level tags** (CM360) — The platform generates tags per placement, not per creative. The caller passes `media_buy_id` and optionally `package_id` to provide the trafficking context. A CM360 adapter uses the media buy context to produce a tag scoped to the target format.

The choice between these models is often a campaign context decision, not a platform constraint. The same creative agent may produce different tag types depending on the caller's needs:

| Use case                                  | Tag type         | `build_creative` parameters                                            |
| ----------------------------------------- | ---------------- | ---------------------------------------------------------------------- |
| Agency/programmatic (unknown destination) | Universal        | `creative_id` + `target_capability_id`                                 |
| Publisher template (known placement)      | Single placement | `creative_id` + `target_capability_id`                                 |
| Publisher template (multiple sizes)       | Multi-placement  | `creative_id` + `target_capability_id`                                 |
| Ad server with trafficking context        | Placement-level  | `creative_id` + `target_capability_id` + `media_buy_id` + `package_id` |

In all cases the output is the same: a creative manifest with the serving code in an `html` or `javascript` asset.

### Variable models

Platforms represent dynamic content differently. The creative protocol's `variables` array accommodates the common patterns:

**Named variable slots** (Flashtalking) — Each creative has explicit variables with IDs, names, and types. Maps directly to `creative-variable.json`.

**Template object properties** (Celtra) — Templates define `templateObjects` with typed `properties` (text, color, image, video, percentage, hidden) scoped to specific components and size variants. A Celtra adapter flattens these into the `variables` array, using the template object label and property label to construct `variable_id` and `name`.

**Rule-based asset selection** (CM360) — Dynamic creatives use `dynamicAssetSelection` with targeting rules, fed by data feeds. This model is not variable-based — CM360 adapters would typically not populate the `variables` array, and `has_variables` filtering would not apply.

### Macro handling

Platforms use their own macro syntax internally. The `macro_values` parameter in `build_creative` lets the caller pass universal macro values (e.g., `CLICK_URL`) that the creative agent substitutes into the output tag using whatever syntax the platform expects.

| Universal macro | CM360 equivalent | Flashtalking equivalent |
| --------------- | ---------------- | ----------------------- |
| `CLICK_URL`     | `%c`             | `[clickTag]`            |
| `CACHEBUSTER`   | `%n`             | `[timestamp]`           |
| `TIMESTAMP`     | `%t`             | `[timestamp]`           |

The creative agent handles translation — callers always use universal macros.

### Re-submission after rejection

When `sync_creatives` or creative review results in a rejection, the fix-and-resubmit flow uses upsert semantics:

1. Check rejection reason via `list_creatives` (library `status: "rejected"`) or `get_media_buys` (package `approval_status: "rejected"` with `rejection_reason`)
2. Fix the creative (update assets, adjust copy, replace media)
3. Re-submit via `sync_creatives` with the same `creative_id` — the agent updates the existing creative and re-triggers review
4. Poll `list_creatives` until `status` transitions from `pending_review` to `approved` or `rejected`

Re-submission resets the review clock. The agent treats the updated creative as a new submission for review purposes.

### Which tasks to implement

The table below maps each interaction model to the tasks it should implement. See [Three interaction models](#three-interaction-models) above for detailed descriptions.

| Interaction model         | Required tasks                                                 | Additional tasks                            | Capabilities                    |
| ------------------------- | -------------------------------------------------------------- | ------------------------------------------- | ------------------------------- |
| Template/transformer      | `get_adcp_capabilities`, `list_transformers`, `build_creative` | `preview_creative`                          | `supports_transformation: true` |
| Ad server                 | `get_adcp_capabilities`, `list_creatives`, `build_creative`    | `preview_creative`, `get_creative_delivery` | `has_creative_library: true`    |
| Sales agent with creative | `get_adcp_capabilities`, `get_products`, `sync_creatives`      | `preview_creative`, `get_creative_delivery` | `has_creative_library: true`    |
| Generative creative tool  | `get_adcp_capabilities`, `build_creative`                      | `list_transformers`, `preview_creative`     | `supports_generation: true`     |

Declare these capabilities in `get_adcp_capabilities` so buyer agents can determine the correct interaction model without trial and error. See [Interaction models](/dist/docs/3.2.0-beta.0/creative/specification#interaction-models) in the spec.

Platforms with a creative library should also implement the [accounts protocol](/dist/docs/3.2.0-beta.0/accounts/overview) so buyers can establish access before querying. This is the same accounts protocol used by sales agents for media buys.

## Related

* [Creative Formats](/dist/docs/3.2.0-beta.0/creative/formats) - Understanding format structure
* [Creative Manifests](/dist/docs/3.2.0-beta.0/creative/creative-manifests) - How manifests work
* [Asset Types](/dist/docs/3.2.0-beta.0/creative/asset-types) - Asset specifications
* [Deprecated list\_creative\_formats task](/dist/docs/3.2.0-beta.0/creative/task-reference/list_creative_formats) - 3.x compatibility guidance
* [list\_creatives task](/dist/docs/3.2.0-beta.0/creative/task-reference/list_creatives) - Creative library API reference
* [build\_creative task](/dist/docs/3.2.0-beta.0/creative/task-reference/build_creative) - Manifest generation API reference
* [preview\_creative task](/dist/docs/3.2.0-beta.0/creative/task-reference/preview_creative) - Preview rendering API reference
