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

# Migrating catalogs

> Migrate AdCP catalogs from v2 to v3. Replaces promoted_offerings with first-class catalog objects, sync_catalogs task, and format-level catalog requirements.

# Migrating catalogs

AdCP 3.0 removes the `promoted_offerings` creative asset type and the `promoted_offering` string field from media buys and creative manifests. Catalogs are now first-class protocol objects with their own sync task, format-level requirements, and conversion event alignment.

## What changed

| v2 field                                          | v3 field                                       | Change type |
| ------------------------------------------------- | ---------------------------------------------- | ----------- |
| `promoted_offerings` (creative asset type)        | `catalog` assets in creative manifest `assets` | Replaced    |
| `promoted_offering` (string on media-buy)         | Removed                                        | Removed     |
| `promoted_offering` (string on creative-manifest) | `catalog` assets in `assets`                   | Replaced    |
| No catalog sync                                   | `sync_catalogs` task                           | New         |
| No format catalog requirements                    | `catalog` asset type on Format `assets`        | New         |
| No catalog-event linking                          | `conversion_events` on Catalog                 | New         |

***

## Creative manifests

### What changed

In v2, catalog data was embedded inside `creative_manifest.assets` as a `promoted_offerings` object that bundled brand identity, inline offerings, and SI agent URL together.

In v3, brand identity is a first-class parameter on tasks (`build_creative`, `sync_creatives`), and catalogs are included as `catalog` asset types in the manifest's `assets`.

### Before (v2)

```json theme={null}
{
  "creative_id": "product-carousel",
  "format_id": {
    "agent_url": "https://creatives.example.com",
    "id": "product_carousel"
  },
  "assets": {
    "promoted_offerings": {
      "brand": {
        "domain": "acmecorp.example.com"
      },
      "offerings": [
        {
          "offering_id": "winter-sale",
          "name": "Winter Sale Collection",
          "description": "50% off all winter items"
        }
      ]
    }
  }
}
```

### After (v3)

```json theme={null}
{
  "$schema": "/schemas/core/creative-manifest.json",
  "format_id": {
    "agent_url": "https://creatives.example.com",
    "id": "product_carousel"
  },
  "assets": {
    "product_catalog": {
      "asset_type": "catalog",
      "type": "product",
      "catalog_id": "winter-products"
    }
  }
}
```

Key differences:

* **Brand identity** comes from the `brand` parameter on the task, not embedded in creative assets
* **Catalogs** are `catalog` asset types in the `assets` map, keyed by a role name (e.g., `product_catalog`)
* **Catalog references synced data** by `catalog_id` instead of inlining items (though inline items are still supported for simple cases)

***

## Media buys

### What changed

The `promoted_offering` string field is removed from media buy objects. What's being promoted is now expressed through the `brief` on `get_products`/`create_media_buy` and through catalog references on creatives.

### Before (v2)

```json theme={null}
{
  "media_buy_id": "mb_123",
  "promoted_offering": "Winter Sale Collection",
  "status": "draft",
  "total_budget": {
    "amount": 10000,
    "currency": "USD"
  },
  "packages": []
}
```

### After (v3)

```json theme={null}
{
  "media_buy_id": "mb_123",
  "status": "draft",
  "total_budget": {
    "amount": 10000,
    "currency": "USD"
  },
  "packages": []
}
```

If you were using `promoted_offering` for reporting or display purposes, that context now comes from:

* The `brief` field on `get_products` and `create_media_buy`
* The `brand` parameter on tasks
* Catalog assets in creative manifest `assets`

***

## Syncing catalogs (new in v3)

The `sync_catalogs` task lets buyers push catalog data to sellers before submitting creatives. This replaces the pattern of embedding product data inside creative assets.

Key features:

* **Bulk sync** with per-catalog results
* **Async approval** workflow (working, input-required, submitted)
* **Item-level review** with approve/reject per catalog item
* **Discovery mode** — omit the catalogs field to see existing synced catalogs
* **Validation modes** — strict, lenient, or dry\_run

### Workflow

```
list_creative_formats → check catalog assets → sync_catalogs → sync_creatives with catalog assets
```

1. Discover what catalogs a format needs via `catalog` asset types in the format's `assets`
2. Sync those catalogs using `sync_catalogs`
3. Wait for approval if the seller requires review
4. Submit creatives that reference the synced `catalog_id`

<Card title="Catalogs documentation" icon="arrow-right" href="/docs/creative/catalogs">
  Complete reference including all 13 catalog types, sync workflow, and item-level review.
</Card>

***

## Format catalog requirements (new in v3)

Formats declare catalog needs as `catalog` asset types in their `assets` array:

```json theme={null}
{
  "assets": [
    {
      "item_type": "individual",
      "asset_id": "product_catalog",
      "asset_type": "catalog",
      "required": true,
      "requirements": {
        "catalog_type": "product",
        "min_items": 3,
        "required_fields": ["name", "price", "image_url"]
      }
    }
  ]
}
```

Format declarations use `asset_type: "catalog"` with a `requirements` object containing:

| Field             | Type      | Description                                                             |
| ----------------- | --------- | ----------------------------------------------------------------------- |
| `catalog_type`    | string    | Required. The catalog type (e.g., `product`, `store`, `job`)            |
| `min_items`       | integer   | Minimum items the catalog must contain                                  |
| `max_items`       | integer   | Maximum items the format can render                                     |
| `required_fields` | string\[] | Fields that must be present on every item                               |
| `feed_formats`    | string\[] | Accepted feed formats (e.g., `google_merchant_center`, `linkedin_jobs`) |

This replaces the v2 pattern where formats implicitly required `promoted_offerings` in their assets — the requirement is now explicit and discoverable.

### Creative agent migration

Creative agents that read format definitions to determine catalog requirements need to change how they discover and fulfill catalog slots.

**Before (v2)** — checking a dedicated `catalog_requirements` field:

```javascript theme={null}
// v2: catalog requirements were a separate top-level array
for (const req of format.catalog_requirements) {
  const catalogType = req.catalog_type;
  const minItems = req.min_items;
}
```

**After (v3)** — iterating the `assets` array and filtering by `asset_type`:

```javascript theme={null}
// v3: catalogs are assets like any other
const catalogAssets = format.assets.filter(a => a.asset_type === "catalog");
for (const slot of catalogAssets) {
  const catalogType = slot.requirements.catalog_type;
  const minItems = slot.requirements.min_items;
  const slotId = slot.asset_id; // use as key in manifest.assets
}
```

When building a manifest, catalog assets are keyed by their `asset_id` from the format definition:

```json theme={null}
{
  "assets": {
    "product_catalog": {
      "type": "product",
      "catalog_id": "winter-products"
    }
  }
}
```

The `asset_id` (e.g., `product_catalog`) from the format's `assets` array becomes the key in the manifest's `assets` object.

***

## Conversion event alignment (new in v3)

Catalogs declare which event types represent conversions for their items:

```json theme={null}
{
  "catalog_id": "job-feed",
  "type": "job",
  "content_id_type": "job_id",
  "conversion_events": ["submit_application", "complete_registration"]
}
```

This links catalogs to the conversion tracking system. When a `log_event` is sent with `content_ids` matching catalog items, the platform knows which events to attribute.

The `content_id_type` field declares what identifier type `content_ids` values represent. For vertical catalogs, this matches the item's canonical ID field (`job_id`, `hotel_id`, etc.). For product catalogs, it distinguishes between `sku` and `gtin` for cross-retailer matching. Omit when using a custom identifier scheme.

| Catalog type  | Typical conversion events                     |
| ------------- | --------------------------------------------- |
| `product`     | `purchase`, `add_to_cart`                     |
| `hotel`       | `purchase` (booking)                          |
| `flight`      | `purchase` (booking)                          |
| `job`         | `submit_application`                          |
| `vehicle`     | `lead`, `schedule`                            |
| `real_estate` | `lead`, `schedule`                            |
| `education`   | `submit_application`, `complete_registration` |
| `destination` | `purchase` (booking)                          |

<Card title="Conversion events" icon="arrow-right" href="/docs/creative/catalogs#conversion-events">
  Full documentation on catalog-event alignment.
</Card>

***

## product\_selectors replaced by catalog on get\_products

The `product_selectors` field on `get_products` has been replaced by `catalog`. The `PromotedProducts` schema has been removed.

### Before

```json theme={null}
{
  "brand": { "domain": "acmecorp.com" },
  "product_selectors": {
    "manifest_gtins": ["00013000006040"],
    "manifest_tags": ["organic"]
  }
}
```

### After

```json theme={null}
{
  "brand": { "domain": "acmecorp.com" },
  "catalog": {
    "type": "product",
    "gtins": ["00013000006040"],
    "tags": ["organic"]
  }
}
```

### Field mapping

| Old (`product_selectors`) | New (`catalog`) |
| ------------------------- | --------------- |
| `manifest_gtins`          | `gtins`         |
| `manifest_skus`           | `ids`           |
| `manifest_tags`           | `tags`          |
| `manifest_category`       | `category`      |
| `manifest_query`          | `query`         |

### Response changes

* `product_selectors_applied` is now `catalog_applied`
* `catalog_match.matched_skus` is now `catalog_match.matched_ids`

***

## New fields on Product

* **`catalog_types`** — Array of catalog types this product supports (e.g., `["product"]`, `["job", "offering"]`)
* **`catalog_match.matched_ids`** — Generic item ID matches (replaces `matched_skus`)
* **`catalog_match.matched_count`** — Count of matched items

***

## Catalog on packages

Packages now accept a `catalog` field for catalog-driven campaigns. One budget envelope promotes an entire catalog, with the platform optimizing delivery across items.

***

## Store catchment targeting

`targeting_overlay` now supports `store_catchments` — referencing synced store catalogs for proximity targeting.

***

## Per-catalog-item delivery

`get_media_buy_delivery` now includes `by_catalog_item` breakdowns within packages for catalog-driven campaigns.

***

## Migration steps

<Steps>
  <Step title="Remove promoted_offerings from creative assets">
    Remove `promoted_offerings` objects from `creative_manifest.assets`. Brand identity is now provided via the `brand` task parameter.
  </Step>

  <Step title="Add catalog assets to creative manifests">
    For creatives that render catalog items (product carousels, store locators, etc.), add catalog assets to the manifest's `assets` map. Each catalog asset is a catalog object with `type` and `catalog_id` (e.g., `{ "type": "product", "catalog_id": "winter-products" }`).
  </Step>

  <Step title="Remove promoted_offering from media buys">
    Remove the `promoted_offering` string from `create_media_buy` requests. Use the `brief` field to describe what's being promoted.
  </Step>

  <Step title="Discover catalog requirements">
    Call `list_creative_formats` and check for `catalog` asset types in each format's `assets` to understand what catalog types and fields are needed.
  </Step>

  <Step title="Sync catalogs before submitting creatives">
    Use the `sync_catalogs` task to push catalog data to sellers. Handle async approval if the seller requires review.
  </Step>

  <Step title="Add conversion events and content ID type for attribution">
    Include `conversion_events` on catalogs to link catalog items to your conversion tracking setup. Add `content_id_type` to declare what identifier type (e.g., `sku`, `gtin`, `job_id`) the event's `content_ids` should be matched against.
  </Step>

  <Step title="Validate against v3 schemas">
    Ensure creative manifests, media buys, and catalog objects validate against v3 schemas.
  </Step>
</Steps>

***

**Related:** [Channels](/docs/reference/migration/channels) | [Pricing](/docs/reference/migration/pricing) | [Geo targeting](/docs/reference/migration/geo-targeting) | [Creatives](/docs/reference/migration/creatives) | [Attribution](/docs/reference/migration/attribution) | [AdCP 3.0 overview](/docs/reference/whats-new-in-v3)
