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

# Campaign Targeting

> Attach structured targeting intent to a campaign through the V3 MCP surface

## Overview

You can attach structured **targeting intent** to a campaign when creating or updating it through the V3 MCP surface (`save_campaign` on `/mcp/v3`). Targeting records what the campaign *intends* to reach — geography, language, device type, daypart, and demographic dimensions — and persists that intent with the campaign object.

<Note>
  Campaign targeting is stored and returned on the campaign workspace. When you
  create a media buy with `save_media_buy`, its targeting can narrow the V3
  campaign overlay but can never widen it.
</Note>

## Passing targeting to save\_campaign

The `targeting` parameter is optional. Omit it to leave targeting unset; include it to attach one or more dimensions:

```json theme={null}
{
  "targeting": {
    "geo": [
      {
        "requirementId": "geo-us-only",
        "strength": "required",
        "include": ["US"]
      }
    ],
    "device": [
      {
        "requirementId": "ctv-preferred",
        "strength": "preferred",
        "include": ["ctv"]
      }
    ],
    "language": [
      {
        "requirementId": "en-only",
        "strength": "required",
        "include": ["en"]
      }
    ]
  }
}
```

Each dimension is an array of **requirement entries**. A requirement entry has:

| Field | Type | Description |
| - | - | - |
| `requirementId` | string | A stable, caller-assigned ID for this requirement. Use it to identify the entry in future updates. |
| `strength` | `"required"` \| `"preferred"` | Whether the dimension is a hard constraint or a preference. |
| `include` | string\[] | Values to target (must include at least one). |
| `exclude` | string\[] | Values to exclude (optional). |

## Supported dimensions

| Dimension | Values |
| - | - |
| `geo` | ISO 3166-1 alpha-2 country codes (e.g. `"US"`, `"CA"`) and DMA codes |
| `language` | BCP-47 language tags (e.g. `"en"`, `"fr"`) |
| `device` | `"ctv"`, `"mobile"`, `"desktop"` |
| `dayparts` | Day-of-week and hour-of-day slots |
| `demographics` | Demographic segment identifiers |

## Reading targeting back

After save, `targetingOverlay` appears on the campaign workspace returned by `save_campaign` and by `get(kind: "campaign")`. Existing campaigns with no targeting set omit the field entirely. The deprecated `targeting` field keeps its existing behavior: it is returned verbatim only when the campaign has stored legacy targeting.

## Updating targeting

Pass `targeting` in a `save_campaign` update to replace the stored targeting intent. Partial dimension updates replace the entire `targeting` object — each call is the full desired state, not a patch.

## Campaign targeting and media buys

`save_media_buy` applies the campaign targeting overlay as a guardrail to each
product's `targetingOverlay`. An explicit product `targetingOverlay` supplies
that buy's targeting, and campaign targeting still narrows it: overlapping
values are kept, and a product value outside the campaign returns `CONFLICT`.
A product can omit a campaign field to inherit it, or narrow it where the field
has defined containment rules. It cannot widen the campaign audience.

`signal_targeting` is excluded from the overlay because it is a priced,
product-scoped selection that will come through the signals path. Typed
`signal_targeting_groups` remains supported.

On a V3 media-buy product overlay: Deprecated. Numeric codes replace names.
Removal will be announced in release notes at least 14 days ahead; planned for
2 November 2026 (AI-10440). Codes must be in the Nielsen DMA dictionary;
unknown codes return nearby code candidates.

For country, region, metro, postal, language, browser, device type, and device
platform includes, the buy uses the overlap. Excludes are combined. A buy's
demographic age range is intersected, unknown ages are included only when both
overlays allow them, and accepted age bases are intersected. The stricter age
restriction wins. Each buy daypart must fit wholly inside a campaign daypart
on the same clock; dayparts are never clipped or converted between timezones.

For proximity, named places, and other structured values without a containment
rule, a product must omit the field or repeat the campaign value exactly.

If the included values for the same field do not overlap, `save_media_buy`
returns a `CONFLICT` error. The error names the field and includes the campaign
and product values so you can correct one of them. It does not create a media
buy that targets everywhere. Omit a product geography field to inherit the
campaign's value for that field.

Language, device, daypart, and demographic campaign intent now participate in
this guardrail. A demographic overlay still cannot dispatch while seller
transport is on AdCP 3.1, so `save_media_buy` rejects it before seller contact.

## Campaign audiences and catalogs

`save_campaign` also accepts `audienceConfig` and `catalogId`. Use
`audienceConfig.targetAudienceIds` to include up to 100 audience IDs and
`audienceConfig.suppressAudienceIds` to exclude up to 100 audience IDs. On an
update, `deleteMissing: true` replaces both lists; otherwise, supplied IDs are
added to the existing lists. `catalogId` is the public catalog ID returned by
the catalog read surfaces; pass `null` on an update to remove it.

Both fields are stored and returned by `get(kind: "campaign")`. Campaigns
with an audience or catalog cannot launch yet because those objects are not
available to sellers. The campaign readiness response names this blocker. Remove
the field to launch without it, or wait for seller object delivery support.

## Rollout and release check

This is available immediately on the public V3 `save_campaign` and
`get(kind: "campaign")` surfaces; it has no separate customer enrollment or
feature flag. The Buyer V3 API release owner verifies the release through the
automated `PR Acceptance Tests` catalog contract proof, then confirms in the
released environment that a campaign can save and read back an audience or
catalog and that a launch attempt returns the seller-sync blocker.

The release check passes only when all three behaviors agree: save persists the
requested IDs, `get` returns them, and launch stays refused while seller sync
is unavailable. Treat a missing readback value, a launch that succeeds, or a
blocker other than the seller-sync refusal as a mitigation trigger. Roll back
the release or remove the audience/catalog from the affected campaign; do not
override the blocker or treat the objects as delivered.

## Backward compatibility

`targeting` is deprecated, but its behavior is unchanged. `targetingOverlay`
is the new V3 targeting field. Its removal is a separately announced change
(AI-10440) with at least 14 days' notice. Existing calls and campaigns are not
affected.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.