> ## 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.

# get_adcp_capabilities

> get_adcp_capabilities is the first call a buyer makes to discover an AdCP seller's supported protocols, auth model, version, and feature capabilities. Request and response schema reference.

Discover a seller's protocol support and capabilities across all AdCP protocols. This is the first call a buyer should make to understand what a seller supports.

<Info>
  **Why this shape.** Capabilities are organized into \~14 top-level domain keys (one per protocol plus identity and signing infrastructure), with feature flags nested under each domain's `features`/`execution`/etc. sub-namespace. We rejected a flat capability list — it forces every implementer to scan an unbounded surface, and it removes the discoverability that comes from related flags sitting next to each other. New capability flags belong under existing domains, not in new top-level keys; declarations are commitments, not advertisements (the conformance runner probes them). → [Capabilities explorer](/docs/protocol/capabilities-explorer) walks the tree before you propose. → [Design principle: capabilities are commitments](/docs/protocol/design-principles#4-capabilities-are-commitments-declared-under-existing-buckets).
</Info>

**Response Time**: \~2 seconds (configuration lookup)

**Purpose**:

* **AdCP discovery** - Does this agent support AdCP? Which versions?
* **Protocol support** - Which protocols (media\_buy, signals, governance, sponsored\_intelligence, creative, brand)?
* **Auth model** - Does this seller trust the agent directly, or must each operator authenticate independently?
* **Detailed capabilities** - Features, execution integrations, geo targeting, portfolio

<Note>
  **Per-caller authorization is NOT reported here.** `get_adcp_capabilities` returns the seller's surface — everything it *could* do for any authorized caller. To discover what *you* are allowed to do on a specific account (which tasks are callable for your identity, which request fields are modifiable, any named scope like `attestation_verifier`), read the `authorization` object on per-account entries in [`sync_accounts`](/docs/accounts/tasks/sync_accounts) and [`list_accounts`](/docs/accounts/tasks/list_accounts) responses. See [Caller authorization](/docs/accounts/overview#caller-authorization) for the full shape and semantics.
</Note>

**Request Schema**: [`/schemas/v3/protocol/get-adcp-capabilities-request.json`](https://adcontextprotocol.org/schemas/v3/protocol/get-adcp-capabilities-request.json)
**Response Schema**: [`/schemas/v3/protocol/get-adcp-capabilities-response.json`](https://adcontextprotocol.org/schemas/v3/protocol/get-adcp-capabilities-response.json)

## Tool-Based Discovery

AdCP uses native MCP/A2A tool discovery. **The presence of `get_adcp_capabilities` in an agent's tool list indicates AdCP support.**

```
Discovery Flow:
1. Browse agent's tool list (MCP) or skills (A2A)
2. See 'get_adcp_capabilities' tool → Agent supports AdCP
3. Call get_adcp_capabilities → Get version, protocols, features, capabilities
4. Proceed based on returned capabilities
```

This approach:

* Uses standard MCP/A2A mechanisms (no custom extensions)
* Always returns current capabilities (not stale metadata)
* Single source of truth for all capability information

:::note
The agent card extension (`adcp-extension.json`) has been removed in v3. Use tool-based discovery instead.
:::

## Version Negotiation

Sellers declare which major versions they support via `adcp.major_versions` in the response. Buyers declare which version they're using via `adcp_major_version` on the request.

```
Version Negotiation Flow:
1. Buyer calls get_adcp_capabilities with adcp_major_version: 2
2. Seller checks 2 against its major_versions: [2, 3]
3. Version is supported → seller returns capabilities for v2
4. Buyer includes adcp_major_version: 2 on all subsequent requests
```

`adcp_major_version` is an optional field on every AdCP request schema. Buyers SHOULD include it on all requests when interacting with a multi-version seller.

**Seller behavior:**

* If `adcp_major_version` is provided and supported → respond using that version's schemas
* If `adcp_major_version` is provided but unsupported → return `VERSION_UNSUPPORTED` (buyer should call without `adcp_major_version` to discover supported versions)
* If `adcp_major_version` is omitted → assume the highest supported version

**Why major versions, not minor?** Semver policy guarantees backward compatibility within a major version. A seller at 3.1 can serve a buyer at 3.0 without negotiation. The capability model handles feature-level differences — buyers check specific capabilities (targeting systems, features, extensions) rather than version numbers to determine compatibility.

## Request Parameters

| Field                | Type      | Description                                                                                                                                                                                                                                                   |
| -------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `adcp_major_version` | integer   | Optional. The AdCP major version the buyer's payloads conform to. When provided, the seller validates against its `major_versions` and returns `VERSION_UNSUPPORTED` if not in range. When omitted, the seller assumes the highest major version it supports. |
| `protocols`          | string\[] | Optional. Filter to specific protocols (`media_buy`, `signals`, `governance`, `sponsored_intelligence`, `creative`, `brand`). If omitted, returns all supported protocols.                                                                                    |

## Response Structure

### adcp

Core AdCP protocol information:

| Field            | Type       | Description                                                           |
| ---------------- | ---------- | --------------------------------------------------------------------- |
| `major_versions` | integer\[] | **Required.** AdCP major versions supported (e.g., `[3]`)             |
| `idempotency`    | object     | **Required.** Idempotency semantics. See [idempotency](#idempotency). |

#### idempotency

Declares whether this seller honors `idempotency_key` replay protection. From 3.1 onward `idempotency_key` is required on every AdCP task request (read and mutating alike — staged enforcement for reads: SHOULD-reject in 3.1, MUST-reject in 3.2; see [security.mdx § Idempotency](/docs/building/by-layer/L1/security#idempotency)). Mirrors the `request_signing.supported` pattern — a single positive declaration, decoupled from the window detail. Clients MUST NOT assume a default; a seller without this block is non-compliant and should be treated as unsafe for retry-sensitive operations across all call modes.

| Field                | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supported`          | boolean | **Required.** Whether the seller deduplicates replays. When `false`, sending an `idempotency_key` is a no-op — the seller will NOT return `IDEMPOTENCY_CONFLICT` or `IDEMPOTENCY_EXPIRED`, and a naive retry WILL double-process. Buyers MUST use natural-key checks (e.g., `get_media_buys` plus request context such as `context.internal_campaign_id` or package context such as `context.buyer_ref`) before retrying spend-committing operations. |
| `replay_ttl_seconds` | integer | Required when `supported: true`. How long the seller retains a canonical response for a key. Minimum `3600` (1h); recommended `86400` (24h); maximum `604800` (7d).                                                                                                                                                                                                                                                                                   |

```json theme={null}
{
  "adcp": {
    "major_versions": [3],
    "idempotency": { "supported": true, "replay_ttl_seconds": 86400 }
  }
}
```

Sellers that do not support replay dedup declare it explicitly:

```json theme={null}
{
  "adcp": {
    "major_versions": [3],
    "idempotency": { "supported": false }
  }
}
```

**Verifying the declaration.** `idempotency.supported: true` is a trust-bearing claim that enables buyers to safely retry spend-committing operations. A compromised or buggy seller could advertise `true` while silently ignoring keys, causing buyer double-spend on retry. Buyers and conformance runners SHOULD probe the declaration with a deliberate payload-mutation replay: send two requests with the same `idempotency_key` but different canonical payloads — a conformant seller MUST return `IDEMPOTENCY_CONFLICT` on the second. Sellers declaring `supported: true` MUST pass this probe as part of the baseline compliance storyboard before the declaration is considered verified.

### supported\_protocols

AdCP protocols this agent supports. This is the single capability axis — each value both (a) declares which tools the agent implements *and* (b) commits the agent to pass the baseline compliance storyboard at `/compliance/{version}/protocols/{protocol}/`. The runner maps JSON snake\_case → URL kebab-case (`media_buy` → `/compliance/.../protocols/media-buy/`).

```json theme={null}
{
  "supported_protocols": ["media_buy", "creative"]
}
```

Valid values: `media_buy`, `creative`, `signals`, `governance`, `brand`, `sponsored_intelligence`.

See the [Compliance Catalog](/docs/building/verification/compliance-catalog) for every protocol's scope. Support for the [compliance test controller](/docs/building/by-layer/L3/comply-test-controller) is declared via the separate `compliance_testing` capability block (below), not as a protocol value.

### specialisms

Optional specialization claims. Each entry corresponds to a narrow storyboard at `/compliance/{version}/specialisms/{id}/`. Every specialism rolls up to one protocol in `supported_protocols` — claiming `sales-guaranteed` requires `media_buy`. The runner rejects a specialism whose parent protocol is missing.

```json theme={null}
{
  "specialisms": ["sales-guaranteed", "creative-template"]
}
```

See the full [Compliance Catalog](/docs/building/verification/compliance-catalog) for every specialism and the [enum schema](https://adcontextprotocol.org/schemas/v3/enums/specialism.json) for the authoritative list.

### Capability slot gaps

SDK helpers such as `definePlatform` can project a platform implementation into narrower capability slots. Treat those slots as commitments: only declare a slot when the agent can execute the corresponding task path end to end.

If a storyboard or local test vector targets a slot the agent does not declare, the expected conformance outcome is `not_applicable`, not failure. Until runner-side enforcement lands in `adcp-client#2244`, implementers running custom or prerelease suites should add explicit skip gates for vectors outside the declared slot scope. Do not work around a missing slot by declaring it and returning placeholder responses; that turns an honest coverage gap into a failed capability claim.

### account

Account and authentication capabilities. All sellers should declare this section — buyers read it before calling `sync_accounts`, `list_accounts`, or any authenticated task. Even simple publishers need account management to handle billing relationships and sandbox testing.

| Field                    | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supported_billing`      | string\[] | **Required.** Billing models this seller supports: `operator`, `agent`. The buyer must pass one of these values as `billing` in every `sync_accounts` entry.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `require_operator_auth`  | boolean   | Default: `false`. Declares who must authenticate; it does not by itself declare whether OAuth is used, whether `list_accounts` is exposed, or which `sync_accounts` modes are supported. When `true`, each operator authenticates independently and account-scoped calls use seller-assigned `account_id` values because the seller or upstream platform owns the canonical account namespace. If a credential may access more than one account, the seller MUST expose `list_accounts` and buyers MUST resolve an explicit `account_id` before the first account-scoped request. If a credential is bound to exactly one account, the seller SHOULD expose `list_accounts` returning that singleton; a seller MAY omit `list_accounts` only when it provides the same explicit `account_id` through another declared path or out-of-band onboarding. When `false`, the agent is trusted, buyer declares accounts via `sync_accounts`, and subsequent calls pass the natural key (`brand` + `operator`). For sandbox, account-id namespaces use pre-existing test accounts from `list_accounts` or out-of-band setup; buyer-declared accounts use `sync_accounts` with `sandbox: true`. |
| `authorization_endpoint` | string    | OAuth URL for operator authentication. Present when the seller supports OAuth for operator authentication. Relevant when `require_operator_auth: true`; if absent, operators obtain credentials out-of-band (seller portal, API key).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `required_for_products`  | boolean   | Default: `false`. When `true`, the buyer must establish an account before calling `get_products`. When `false`, the buyer can browse products without an account — useful for price comparison and discovery before committing to a seller.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `account_financials`     | boolean   | Default: `false`. When `true`, the seller supports [`get_account_financials`](/docs/accounts/tasks/get_account_financials) for querying spend, credit, and invoice status. Only applicable to operator-billed accounts.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `sandbox`                | boolean   | Default: `false`. Strongly recommended for production sales agents. When `true`, the seller supports sandbox accounts for testing. For sandbox, account-id namespaces discover pre-existing test accounts through `list_accounts` or out-of-band setup; buyer-declared accounts declare sandbox via `sync_accounts` with `sandbox: true` — no real platform calls or spend. See [Sandbox mode](/docs/media-buy/advanced-topics/sandbox).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

#### Auth models

**Buyer-declared accounts** (`require_operator_auth: false`) — The seller trusts the agent's identity claims. The agent authenticates once with its own bearer token, then calls `sync_accounts` to declare which brands and operators it represents. The seller provisions accounts based on the agent's claims, optionally verifying operators against `brand.json`. All subsequent calls use the agent's single credential and pass natural keys (`brand` + `operator`).

**Account-id namespaces** (`require_operator_auth: true`) — Each operator must authenticate with the seller directly. The agent obtains a credential per operator — via OAuth using `authorization_endpoint`, or out-of-band — opens a per-operator session, and passes seller-assigned `account_id` values on subsequent requests. OAuth is credential acquisition, not an account taxonomy axis. Two namespace patterns use the same wire reference: upstream-managed sellers expose `list_accounts`, making explicit account resolution mandatory before account-scoped calls; seller-defined namespaces without `list_accounts` provide account IDs out-of-band. SDKs SHOULD lazily call `list_accounts` when first needed, auto-select a singleton, cache it per credential/session, and still send explicit `AccountRef` values on required-account calls.

For sandbox, the path follows the account namespace: account-id namespaces discover pre-existing test accounts via `list_accounts` or out-of-band setup; buyer-declared accounts declare sandbox via `sync_accounts` with `sandbox: true`.

See [Accounts and Agents](/docs/building/integration/accounts-and-agents#what-sellers-declare) for full workflows and [seller patterns](/docs/building/integration/accounts-and-agents#seller-patterns) for common combinations of auth model and billing support.

### media\_buy

Media-buy protocol capabilities. Only present if `media_buy` is in `supported_protocols`. Sellers declaring `media_buy` should also include `account` (with `supported_billing`) and `media_buy.portfolio` — buyers need both to establish billing and understand inventory coverage. Compliance testing validates their presence.

:::note 3.0 breaking changes
The following fields have been removed from the capabilities response:

* `media_buy.reporting` — Reporting is implied by `media_buy`. Use product-level `reporting_capabilities` instead.
* `features.content_standards` — Replaced by `media_buy.content_standards` object. Presence of the object indicates support.
* `features.audience_targeting` — Replaced by `media_buy.audience_targeting` object. Presence of the object indicates support.
* `features.conversion_tracking` — Replaced by `media_buy.conversion_tracking` object. Presence of the object indicates support.
* `execution.targeting.device_platform`, `device_type` — Implied by `media_buy` support.
* `execution.targeting.audience_include`, `audience_exclude` — Implied by `audience_targeting` object presence.
* `execution.trusted_match.supported` — Object presence indicates support.
* `brand.identity` — Implied by `brand` in `supported_protocols`. `get_brand_identity` is always available.
  :::

#### reporting\_delivery\_methods

Declares which push-based delivery methods are available across the seller's product portfolio. Polling via `get_media_buy_delivery` is a required task for all `media_buy` sellers regardless of this field.

| Method    | Description                                         | Configuration                                      |
| --------- | --------------------------------------------------- | -------------------------------------------------- |
| `webhook` | Seller pushes to buyer-provided URL                 | Buyer configures `reporting_webhook` per media buy |
| `offline` | Seller pushes batch files to a cloud storage bucket | Seller provisions `reporting_bucket` per account   |

When absent, only polling is available. Cadence and metrics are declared per product in `reporting_capabilities`.

When `offline` is declared, also include `offline_delivery_protocols` to declare which cloud storage protocols are supported (`s3`, `gcs`, `azure_blob`). Buyers express a protocol preference via `preferred_reporting_protocol` in `sync_accounts`; the seller provisions the account's `reporting_bucket` using a supported protocol.

For offline delivery, the seller provisions a per-account bucket and grants the buyer read access out-of-band. The bucket location (including `file_retention_days`) appears on the account object returned by `sync_accounts` as `reporting_bucket`. See [Offline File Delivery](/docs/media-buy/media-buys/optimization-reporting#offline-file-delivery-based-reporting) for details.

#### creative\_approval\_mode

Declares the seller's tenant-wide creative approval posture after creatives are assigned and automated validation passes. This is not a notification surface or a new approval workflow; it tells buyers and compliance runners whether human review can still block serving eligibility. Compliance runners use this declaration mainly to decide whether auto-approval-dependent storyboards such as `media_buy_seller/pending_creatives_to_start` apply.

| Value           | Description                                                                                                                                                                              |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auto_approve`  | Human review does not block serving eligibility after creatives are assigned and automated validation passes. Auto-approval-dependent storyboards can run.                               |
| `require_human` | One or more products/accounts may require manual review before creatives become eligible to serve. Treat this as a tenant-wide worst-case ceiling until a product-level override exists. |

Sellers with mixed approval policies SHOULD declare `require_human` unless every product/account that can be reached by the advertised agent supports automatic eligibility after automated validation. When the field is absent, approval behavior is legacy-unspecified; runners SHOULD NOT treat omission as an affirmative `auto_approve` claim. `ai_assisted` is intentionally not a value until the protocol defines what assistance changes in observable behavior.

#### features

Optional media-buy features. **If declared true, seller MUST honor requests using that feature.**

| Feature                      | Description                                                                            |
| ---------------------------- | -------------------------------------------------------------------------------------- |
| `inline_creative_management` | Accepts creatives inline in `create_media_buy` and `update_media_buy` package payloads |
| `property_list_filtering`    | Honors `property_list` parameter in `get_products`                                     |
| `catalog_management`         | Supports `sync_catalogs` for catalog feed management                                   |

#### content\_standards

Content standards implementation details. Presence of this object indicates the seller supports content\_standards configuration including sampling rates and category filtering. Gives buyers pre-buy visibility into local evaluation and artifact delivery capabilities.

| Field                       | Type      | Description                                                                                                                                                                             |
| --------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supports_local_evaluation` | boolean   | Whether the seller runs a local evaluation model. When `false`, `local_verdict` will always be `unevaluated` and the `failures_only` filter on `get_media_buy_artifacts` is not useful. |
| `supported_channels`        | string\[] | Channels for which the seller can provide content artifacts. Helps buyers understand which parts of a mixed-channel buy will have content standards coverage.                           |
| `supports_webhook_delivery` | boolean   | Whether the seller supports push-based artifact delivery via `artifact_webhook` configured at buy creation time.                                                                        |

**Example:**

```json theme={null}
{
  "content_standards": {
    "supports_local_evaluation": true,
    "supported_channels": ["display", "olv", "podcast"],
    "supports_webhook_delivery": true
  }
}
```

If `supports_local_evaluation` is `false`, the `failures_only` filter on `get_media_buy_artifacts` will return an empty result set — all verdicts will be `unevaluated`.

#### execution

Technical execution capabilities:

| Field              | Type      | Description                                                                                                                                                                       |
| ------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trusted_match`    | object    | [TMP](/docs/trusted-match) support. When present, this seller supports real-time contextual and/or identity matching. Check individual products for per-product TMP capabilities. |
| `axe_integrations` | string\[] | Deprecated. Legacy AXE URLs this seller can execute through. Use `trusted_match` for new integrations.                                                                            |
| `creative_specs`   | object    | Creative specification support (VAST versions, MRAID, etc.)                                                                                                                       |
| `targeting`        | object    | Targeting capabilities (geo granularity)                                                                                                                                          |

##### axe\_integrations

`axe_integrations` is an array of Agentic Ad Exchange (AXE) endpoint URLs that this seller can execute through. AXE is the real-time execution layer for AdCP campaigns — it connects buyer agents to programmatic inventory via standardized exchanges.

When a seller declares AXE URLs in their capabilities, buyers can:

* Route impression-level execution through the declared exchange
* Use the exchange's targeting, optimization, and measurement capabilities
* Execute alongside the seller's direct-sold inventory

Buyers discover AXE support via `get_adcp_capabilities` and filter products to AXE-enabled sellers using `required_axe_integrations` on [`get_products`](/docs/media-buy/task-reference/get_products).

##### creative\_specs

| Field            | Type      | Description                                             |
| ---------------- | --------- | ------------------------------------------------------- |
| `vast_versions`  | string\[] | VAST versions supported (e.g., `["4.0", "4.1", "4.2"]`) |
| `mraid_versions` | string\[] | MRAID versions supported                                |
| `vpaid`          | boolean   | VPAID support                                           |
| `simid`          | boolean   | SIMID support                                           |

##### targeting

| Field               | Type    | Description                                                                                                    |
| ------------------- | ------- | -------------------------------------------------------------------------------------------------------------- |
| `geo_countries`     | boolean | Country-level targeting using ISO 3166-1 alpha-2 codes                                                         |
| `geo_regions`       | boolean | Region/state-level targeting using ISO 3166-2 codes (e.g., `US-NY`, `GB-SCT`)                                  |
| `geo_metros`        | object  | Metro area targeting with system-specific support                                                              |
| `geo_postal_areas`  | object  | Postal area targeting with country and precision support                                                       |
| `age_restriction`   | object  | Age restriction capabilities with `supported` flag and `verification_methods`                                  |
| `language`          | boolean | Language targeting (ISO 639-1 codes)                                                                           |
| `keyword_targets`   | object  | Keyword targeting with `supported_match_types` array (`broad`, `phrase`, `exact`). Presence indicates support. |
| `negative_keywords` | object  | Negative keyword targeting with `supported_match_types` array. Presence indicates support.                     |
| `geo_proximity`     | object  | Proximity targeting from arbitrary coordinates (see below)                                                     |

Device platform and device type targeting are implied by `media_buy` support. Audience include/exclude targeting is implied by the presence of the `audience_targeting` capabilities object.

Sellers that support a geographic targeting level SHOULD support both inclusion and exclusion at that level. For example, `geo_metros.nielsen_dma: true` SHOULD mean the seller supports both `geo_metros` and `geo_metros_exclude` with Nielsen DMA codes. If a seller only supports one direction (e.g., inclusion but not exclusion), it MUST return a validation error for unsupported fields rather than silently ignoring them. See [Targeting Overlays](/docs/media-buy/advanced-topics/targeting) for exclusion semantics.

**geo\_proximity** specifies which proximity targeting methods are supported:

| Field             | Type      | Description                                                                                   |
| ----------------- | --------- | --------------------------------------------------------------------------------------------- |
| `radius`          | boolean   | Simple radius targeting (distance circle from a point)                                        |
| `travel_time`     | boolean   | Travel time isochrone targeting (requires a routing engine)                                   |
| `geometry`        | boolean   | Pre-computed GeoJSON geometry (buyer provides the polygon)                                    |
| `transport_modes` | string\[] | Transport modes supported for isochrones: `driving`, `walking`, `cycling`, `public_transport` |

**geo\_metros** specifies which metro classification systems are supported:

| System           | Description                                        |
| ---------------- | -------------------------------------------------- |
| `nielsen_dma`    | Nielsen DMA codes (US market, e.g., `501` for NYC) |
| `uk_itl1`        | UK ITL Level 1 regions                             |
| `uk_itl2`        | UK ITL Level 2 regions                             |
| `eurostat_nuts2` | Eurostat NUTS Level 2 regions (EU)                 |

**geo\_postal\_areas** specifies which country-local postal code systems are supported. The preferred shape is keyed by ISO 3166-1 alpha-2 country, with each country listing supported systems:

```json theme={null}
{
  "us_zip": true,
  "us_zip_plus_four": true,
  "US": ["zip", "zip_plus_four"],
  "GB": ["outward", "full"],
  "CA": ["fsa", "full"],
  "ZA": ["postal_code"]
}
```

Use `postal_code` for the normal postal code string in countries without a more specific registered local system. During the 3.x migration, sellers SHOULD emit equivalent deprecated aliases such as `us_zip` alongside native country keys where an alias exists. Buyers and SDKs SHOULD normalize both shapes before making capability decisions.

#### audience\_targeting

Audience targeting capabilities. Presence of this object indicates the seller supports audience targeting, including `sync_audiences` and `audience_include`/`audience_exclude` in targeting overlays. Describes what identifier types the seller accepts for audience matching, size constraints, and expected matching latency.

| Field                           | Type      | Required     | Description                                                                                                                                                                                                                                                                                                                                                                                                               |
| ------------------------------- | --------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supported_identifier_types`    | string\[] | **Required** | PII-derived identifier types accepted for audience matching. Buyers should only send identifiers the seller supports. Values: `hashed_email`, `hashed_phone`.                                                                                                                                                                                                                                                             |
| `minimum_audience_size`         | integer   | **Required** | Minimum matched audience size required for targeting. Audiences below this threshold will have `status: too_small`. Varies by platform (100–1000 is typical).                                                                                                                                                                                                                                                             |
| `supports_platform_customer_id` | boolean   |              | When `true`, the seller accepts the buyer's CRM/loyalty ID as a matchable identifier. Only applicable when the seller operates a closed ecosystem with a shared ID namespace (e.g., a retailer matching against their loyalty program). Buyers can include `platform_customer_id` values in `AudienceMember.identifiers`. Reporting on matched IDs typically requires a clean room or the seller's own reporting surface. |
| `supported_uid_types`           | string\[] |              | Universal ID types accepted for audience matching (MAIDs, RampID, UID2, etc.). MAID support varies significantly by platform — check this field before sending `uids` with `type: maid`.                                                                                                                                                                                                                                  |
| `matching_latency_hours`        | object    |              | Expected matching latency range in hours after upload. Use to calibrate polling cadence and set appropriate expectations before configuring `push_notification_config`. Shape: `{ min: integer, max: integer }`.                                                                                                                                                                                                          |

#### conversion\_tracking

Seller-level conversion tracking capabilities. Declares what the seller supports for `kind: "event"` optimization goals.

| Field                          | Type      | Description                                                                                                                                                                                                                                 |
| ------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `multi_source_event_dedup`     | boolean   | Whether the seller can deduplicate events across multiple event sources within a single goal. When `true`, the same `event_id` from multiple sources counts once. When `false` or absent, buyers should use a single event source per goal. |
| `supported_event_types`        | string\[] | Event types this seller can track. If omitted, all standard event types are supported.                                                                                                                                                      |
| `supported_uid_types`          | string\[] | Universal ID types accepted for user matching.                                                                                                                                                                                              |
| `supported_hashed_identifiers` | string\[] | Hashed PII types accepted (`hashed_email`, `hashed_phone`). Buyers must hash before sending (SHA-256, normalized).                                                                                                                          |
| `supported_action_sources`     | string\[] | Action sources this seller accepts events from.                                                                                                                                                                                             |
| `attribution_windows`          | object\[] | Available attribution windows. Single-element arrays indicate fixed windows; multi-element arrays indicate configurable options the buyer can choose from via `attribution_window` on optimization goals.                                   |

#### portfolio

Inventory portfolio information:

| Field                  | Type      | Description                                            |
| ---------------------- | --------- | ------------------------------------------------------ |
| `publisher_domains`    | string\[] | **Required.** Publisher domains this seller represents |
| `primary_channels`     | string\[] | Main advertising channels                              |
| `primary_countries`    | string\[] | Main countries (ISO codes)                             |
| `description`          | string    | Markdown portfolio description                         |
| `advertising_policies` | string    | Content policies and restrictions                      |

### signals

Signals protocol capabilities. Only present if `signals` is in `supported_protocols`.

| Field                      | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data_provider_domains`    | string\[] | Data provider domains this signals agent is authorized to resell. Buyers should fetch each provider's `adagents.json` for signal definitions and to verify authorization.                                                                                                                                                                                                                                                                                                                             |
| `discovery_modes`          | string\[] | Discovery modes the agent supports on `get_signals`. `"brief"` (semantic discovery via `signal_spec` / `signal_refs`, with deprecated `signal_ids` accepted for older clients) is implicit and always supported. Declare `"wholesale"` to advertise that callers can omit `signal_spec` / `signal_refs` / `signal_ids` and enumerate the full priced signals feed. Agents not declaring `"wholesale"` MAY return `INVALID_REQUEST` for wholesale calls. Absent declaration is treated as `["brief"]`. |
| `features.catalog_signals` | boolean   | **Deprecated.** Legacy wire flag for structured `signal_ref` references to provider-published signal definitions in adagents.json `signals[]`.                                                                                                                                                                                                                                                                                                                                                        |

<Note>
  `catalog_signals` is deprecated. Existing 3.x agents may continue to emit it for compatibility, but new agents SHOULD omit it and callers MUST NOT require it before using `signal_ref`. Treat `supported_protocols: ["signals"]`, `signals.data_provider_domains`, `signals.discovery_modes`, and the actual `get_signals` response as the capability surface.
</Note>

### creative

Creative protocol capabilities. Only present if `creative` is in `supported_protocols`.

| Field                         | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supports_compliance`         | boolean | When `true`, this creative agent can process briefs with compliance requirements (`required_disclosures`, `prohibited_claims`) and will validate that disclosures can be satisfied by the target format. Use the `disclosure_positions` filter on `list_creative_formats` to find compatible formats.                                                                                                                                                                                                                                                                                                               |
| `supports_transformers`       | boolean | When `true`, this creative agent offers account-scoped transformers — the selectable units of build capability (voices, models, styles) discovered via [`list_transformers`](/docs/creative/task-reference/list_transformers) and selected with `transformer_id` (plus the typed `config` bag) on [`build_creative`](/docs/creative/task-reference/build_creative). When `false` or absent, the agent does not expose transformers; `list_transformers` is unavailable and `build_creative` ignores `transformer_id`/`config`. Pre-call discriminator for routing across creative agents.                           |
| `supports_refinement`         | boolean | When `true`, this creative agent retains produced `build_variant` leaves (for an agent-defined window) and can re-build from one via `refine_from_build_variant_id` on [`build_creative`](/docs/creative/task-reference/build_creative) — applying a natural-language instruction in `message` plus an optional `config` delta, returning new lineage-linked variants. A build-time capability independent of generation/transformation. When `false` or absent, `refine_from_build_variant_id` returns `UNSUPPORTED_FEATURE`; refine via the transform path (`creative_manifest` + `message`) instead.             |
| `refinable_retention_seconds` | integer | When `supports_refinement` is `true`, the **guaranteed-minimum** window (a floor, not a ceiling) during which a produced `build_variant_id` stays refinable via `refine_from_build_variant_id`. A ref within the window SHOULD resolve; the agent MAY retain longer. Omit to leave the window agent-defined (buyers treat refinability as best-effort and handle `REFERENCE_NOT_FOUND`).                                                                                                                                                                                                                            |
| `multiplicity`                | object  | Pre-call fan-out discriminators so a buyer knows before sending `max_creatives`/`max_variants`: `supports_catalog_fanout` + `max_creatives_limit`, `supports_variants` + `max_variants_limit`, and `variant_dimensions[]` (which `variant_axis.dimension` values are supported). Over-limit requests are **clamped** to the ceilings (shortfall shown via `items_returned` \< `items_total`), not rejected. Absent means no fan-out — `build_creative` produces a single creative. Individual transformers may narrow this via `transformer.multiplicity`.                                                          |
| `supports_spend_controls`     | boolean | When `true`, `build_creative` honors a per-call `max_spend` ceiling (returns a partial paid build with `budget_status: "capped"` + a `BUDGET_CAP_REACHED` advisory rather than overspending) and supports `mode: "estimate"` dry-runs (a projected cost band, producing/billing nothing). When `false` or absent, both are rejected with `UNSUPPORTED_FEATURE`. Meaningful only with `bills_through_adcp: true`.                                                                                                                                                                                                    |
| `bills_through_adcp`          | boolean | When `true`, this creative agent bills through the AdCP rate-card surface — `list_creatives` returns `pricing_options` (with `include_pricing=true` and an authenticated account), `build_creative` populates `pricing_option_id` and `vendor_cost`, and `report_usage` accepts records against the rate card. When `false` or absent, the agent bills out of band (flat license, SaaS contract, bundled enterprise agreement); buyers should skip pricing fields and tolerate `report_usage` returning `accepted: 0` with `BILLING_OUT_OF_BAND` errors. Pre-call discriminator for routing across creative agents. |

### governance

Governance protocol capabilities. Only present if `governance` is in `supported_protocols`. Governance agents declare capabilities across four domains: property evaluation, creative evaluation, content standards verification, and policy registry integration.

#### property\_features

Array of property features this governance agent can evaluate. See [Property Governance](/docs/governance/property/index).

| Field             | Type      | Description                                                                                                                                                                                   |
| ----------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `feature_id`      | string    | **Required.** Unique identifier (e.g., `mfa_score`, `coppa_certified`). Use `registry:{policy_id}` prefix for features mapped to [Policy Registry](/docs/governance/policy-registry) entries. |
| `type`            | string    | **Required.** Data type: `binary`, `quantitative`, or `categorical`                                                                                                                           |
| `range`           | object    | For quantitative: `{ min, max }`                                                                                                                                                              |
| `categories`      | string\[] | For categorical: valid values                                                                                                                                                                 |
| `description`     | string    | Human-readable description                                                                                                                                                                    |
| `methodology_url` | string    | URL to methodology documentation                                                                                                                                                              |

#### creative\_features

Array of creative features this governance agent can evaluate. Same field schema as `property_features`. See [Creative Governance](/docs/governance/creative/index).

Creative governance agents evaluate creatives for security, content categorization, and regulatory compliance. Buyers filter creatives by feature requirements — for example, blocking creatives flagged for `auto_redirect` or requiring `registry:eu_ai_act_article_50` compliance.

#### content\_standards

Content standards verification capabilities. See [Content Standards](/docs/governance/content-standards/index).

| Field                 | Type      | Description                                                                            |
| --------------------- | --------- | -------------------------------------------------------------------------------------- |
| `supported`           | boolean   | Whether this agent can serve as a content standards verification agent                 |
| `calibration_formats` | string\[] | Artifact asset types this agent can evaluate (e.g., `text`, `image`, `video`, `audio`) |

#### policy\_registry

Policy registry integration capabilities. See [Policy Registry](/docs/governance/policy-registry).

| Field       | Type      | Description                                                                                          |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------- |
| `supported` | boolean   | Whether this agent consumes policies from the AdCP Policy Registry                                   |
| `domains`   | string\[] | Governance domains this agent covers (e.g., `campaign`, `property`, `creative`, `content_standards`) |

**Example governance agent response:**

```json theme={null}
{
  "$schema": "/schemas/protocol/get-adcp-capabilities-response.json",
  "status": "completed",
  "adcp": {
    "major_versions": [3],
    "idempotency": { "supported": true, "replay_ttl_seconds": 86400 }
  },
  "supported_protocols": ["governance"],
  "governance": {
    "property_features": [
      { "feature_id": "mfa_score", "type": "quantitative", "range": { "min": 0, "max": 100 }, "description": "Made For Advertising detection (0=quality content, 100=likely MFA)", "methodology_url": "https://vendor.example.com/methodology/mfa" },
      { "feature_id": "coppa_certified", "type": "binary", "description": "COPPA compliance certification" },
      { "feature_id": "registry:uk_hfss", "type": "binary", "description": "UK HFSS advertising restrictions compliance" },
      { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 }, "description": "Carbon footprint sustainability score", "methodology_url": "https://vendor.example.com/methodology/carbon-score" }
    ],
    "creative_features": [
      { "feature_id": "registry:eu_ai_act_article_50", "type": "binary", "description": "EU AI Act Article 50 — AI-generated content disclosure" },
      { "feature_id": "registry:ca_sb_942", "type": "binary", "description": "California SB 942 — AI transparency compliance" },
      { "feature_id": "auto_redirect", "type": "binary", "description": "Detects auto-redirect behavior in creative code" },
      { "feature_id": "credential_harvest", "type": "binary", "description": "Detects credential harvesting patterns" }
    ],
    "content_standards": {
      "supported": true,
      "calibration_formats": ["text", "image", "video"]
    },
    "policy_registry": {
      "supported": true,
      "domains": ["campaign", "property", "creative", "content_standards"]
    }
  }
}
```

### measurement

Experimental measurement protocol capabilities. Only present if `measurement` is in `supported_protocols`; agents implementing it must also list `measurement.core` in `experimental_features`. The `measurement` protocol is currently scoped to `get_adcp_capabilities` for catalog discovery (this block); additional measurement tasks (reporting, attribution, panel queries) and a baseline compliance storyboard land in subsequent minors. The capability block is shipping now so measurement vendors can publish their per-metric catalogs and AAO can crawl them, before the broader task surface is settled.

**Scope.** An agent claiming `measurement` computes one or more quantitative metrics about ad delivery, exposure, or effect (impression verification, viewability, IVT, attention, brand lift, incrementality, outcomes, emissions — vendors define the surface in `metrics[]`). Returns metric definitions (this block), not pricing or coverage (negotiated per buy via `measurement_terms`) and not live values (returned per buy via `vendor_metric_values`). Same mechanical model as `compliance_testing` and `webhook_signing`: presence asserts the capability; the block carries the structured payload.

Measurement agents publish a per-metric catalog so buyers know which metrics each vendor offers. This is the canonical source of truth — AAO crawls it to populate the federated [measurement-vendor index](/docs/registry/index#measurement-vendor-discovery).

#### metrics

Array of metrics this measurement agent computes.

| Field                 | Type         | Description                                                                                                                                                                                                                                                                                                                                                      |
| --------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metric_id`           | string       | **Required.** Vendor-scoped identifier (`attention_units`, `gco2e_per_impression`, etc.) — matches the `metric_id` populated in `vendor_metric_values` on delivery. The full identity is the tuple `(vendor.domain, vendor.brand_id, metric_id)`. Each `metric_id` MUST be unique within a single agent's catalog.                                               |
| `standard_reference`  | string (URI) | Optional URI pointing at the published standard this metric **implements** (IAB Attention Measurement Guidelines, MRC Viewable Impression Measurement, GARM emissions framework). Distinct from `accreditations` below — `standard_reference` is what the metric is built against; `accreditations` is third-party certification of conformance.                 |
| `accreditations`      | object\[]    | Optional list of third-party accreditations this metric holds (MRC, ARF, JIC bodies, ABC, BARB, AGOF, etc.). Each entry: `accrediting_body` (required), optional `certification_id`, `valid_until`, `evidence_url`. Buyers asking "is this MRC-accredited?" SHOULD check this array — implementing a standard is not the same as being independently accredited. |
| `unit`                | string       | Unit of the value when reported in `vendor_metric_values.value` (`score`, `seconds`, `persons`, `gCO2e`, `lift_percent`, `USD`, etc.). Sellers populating `vendor_metric_values.unit` MUST match this declaration.                                                                                                                                               |
| `description`         | string       | Human-readable description of what the metric measures and any methodology notes. AAO and buyer agents normalize across catalogs from this field plus the structured fields above; classification facets are not declared at the metric level.                                                                                                                   |
| `methodology_url`     | string (URI) | URL to vendor's full methodology documentation. Mirrors `governance.property_features[].methodology_url`.                                                                                                                                                                                                                                                        |
| `methodology_version` | string       | Optional version identifier (semver, ISO date, or vendor-defined string) for the methodology. When present, buyer agents can pin a contracted version so silent methodology changes are detectable; absence means the vendor does not version their methodology and buyers MUST treat any change as untracked.                                                   |
| `ext`                 | object       | Vendor extensions per the AdCP `ext` convention.                                                                                                                                                                                                                                                                                                                 |

```json Response example theme={null}
{
  "measurement": {
    "metrics": [
      {
        "metric_id": "attention_units",
        "standard_reference": "https://iabtechlab.com/standards/attention-measurement",
        "accreditations": [
          { "accrediting_body": "MRC", "certification_id": "MRC-ATT-2026-001", "valid_until": "2027-12-31", "evidence_url": "https://mediaratingcouncil.org/accreditations/attentionvendor" }
        ],
        "unit": "score",
        "description": "Eye-tracking-based attention score (0-100). Computed from a panel of 25K opted-in households.",
        "methodology_url": "https://attentionvendor.example/docs/attention-units",
        "methodology_version": "v2.1"
      },
      {
        "metric_id": "engagement_seconds",
        "unit": "seconds",
        "description": "Active dwell time in seconds, measured via in-content telemetry."
      }
    ]
  }
}
```

**Discovery vs. settlement.** Buyers MAY hit a measurement agent's `get_adcp_capabilities` directly to see its current catalog (live, canonical, no staleness), or query AAO's federated index for cross-vendor aggregation. The index trades a TTL refresh window for cross-vendor speed; live calls trade speed for currency. Both are valid — typically planning queries hit the index, settlement/audit queries hit the agent.

**This is a discovery surface, not a rate card.** The catalog tells buyers *what* a vendor measures and *what standards/accreditations* back it. Pricing per impression, minimum measurable inventory, attribution windows, geographic coverage, and data-freshness SLAs are negotiated per buy through the seller's `measurement_terms` on `create_media_buy` — not through this catalog.

### compliance\_testing

Compliance testing capabilities. The presence of this block declares that the agent supports deterministic testing via [`comply_test_controller`](/docs/building/by-layer/L3/comply-test-controller). Omit the block if the agent does not support compliance testing.

**Production deployments MUST NOT include this block.** `comply_test_controller` is sandbox-only at the deployment level; advertising the capability on a production endpoint is non-conformant even if dispatch is gated. See [Compliance test controller § Sandbox gating](/docs/building/by-layer/L3/comply-test-controller#sandbox-gating).

| Field       | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scenarios` | string\[] | Compliance testing scenarios this agent supports. Values SHOULD include every canonical controller scenario the agent implements, excluding `list_scenarios` because that value is a discovery operation rather than a test capability. Current canonical values include `force_creative_status`, `force_account_status`, `force_media_buy_status`, `force_create_media_buy_arm`, `force_task_completion`, `force_session_status`, `simulate_delivery`, `simulate_budget_spend`, `seed_product`, `seed_pricing_option`, `seed_creative`, `seed_plan`, `seed_media_buy`, `seed_creative_format`, `seed_measurement_catalog`, `query_upstream_traffic`, `query_provenance_audit_observations`, and `force_upstream_unavailable`. Values MAY also include implementation-specific scenarios. Runners MUST treat scenario names as open strings — new scenarios may be added in additive releases. |

Storyboard runners check for the `compliance_testing` block before running deterministic testing steps. If the agent does not include the block, controller-dependent storyboard steps cannot be validated.

Agents that implement `comply_test_controller` SHOULD include the `compliance_testing` capability block and list supported scenarios. Agents that only support a subset of scenarios (e.g., media buy status but not SI sessions) declare only those scenarios — the runner reports unsupported scenario coverage as skipped or partial rather than as a hidden pass.

:::note
Compliance testing is sandbox-only at the deployment level — production deployments MUST NOT advertise this block or expose `comply_test_controller` on any surface. `FORBIDDEN` is returned only when an in-sandbox caller passes `params` that reference a non-sandbox account; live-mode probes for the tool by name receive the transport's standard unknown-tool error. See [Sandbox gating](/docs/building/by-layer/L3/comply-test-controller#sandbox-gating).
:::

### webhook\_signing

Declares a seller's webhook-signing posture. Any seller whose capability surface advertises mutating-webhook emission — including but not limited to `media_buy.reporting_delivery_methods` containing `webhook`, `media_buy.content_standards.supports_webhook_delivery: true`, or `wholesale_feed_webhooks.supported: true` — MUST include this block with `supported: true`. A seller that emits no webhooks at all MAY omit the block entirely; the absence of both mutating-webhook emission in other capabilities and this block is an unambiguous "does not emit webhooks" posture. Buyers read the block at onboarding to determine which algorithms to expect per the [AdCP webhook-signing profile](/docs/building/implementation/security#webhook-callbacks). Buyers integrating with a seller that advertises mutating-webhook emission while advertising `supported: false` or omitting this block MUST fail onboarding with a user-actionable error; silent integration with a non-signing-but-webhook-emitting seller is unsafe for any mutating-webhook use case.

| Field                  | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ---------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supported`            | boolean   | **Required when the seller advertises mutating-webhook emission elsewhere in its capability surface.** `true` iff the seller signs outbound webhooks. `false` means the seller emits webhooks but does not sign them; buyers MUST fail onboarding. Sellers that emit no webhooks SHOULD omit the entire block rather than set `supported: false` — `false` is reserved for the unsafe posture of unsigned-webhook emission, not absence-of-webhooks.                                                                                                                                                      |
| `profile`              | string    | **Required when `supported: true`.** The profile version string. Currently `"adcp/webhook-signing/v1"`. Future versions bump the string.                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `algorithms`           | string\[] | **Required when `supported: true`.** Subset of `["ed25519", "ecdsa-p256-sha256"]` — the algorithms this seller will sign webhooks with. Matches the webhook-signing verifier allowlist (see [Verifier checklist for webhooks](/docs/building/implementation/security#webhook-callbacks), step 4). Buyers MUST be prepared to verify any algorithm listed AND MUST reject onboarding with a user-actionable error if an advertised algorithm is outside this enumerated set — a seller advertising an out-of-set algorithm (e.g., `hs256`) is either misconfigured or signalling a non-conforming profile. |
| `legacy_hmac_fallback` | boolean   | **Required when `supported: true`.** `true` iff the seller supports the legacy HMAC-SHA256 scheme when the buyer populates `push_notification_config.authentication.credentials` or `accounts[].notification_configs[].authentication.credentials`. `false` is the recommended posture in 3.x — the HMAC scheme is removed in AdCP 4.0.                                                                                                                                                                                                                                                                   |

**Example:**

```json theme={null}
{
  "webhook_signing": {
    "supported": true,
    "profile": "adcp/webhook-signing/v1",
    "algorithms": ["ed25519", "ecdsa-p256-sha256"],
    "legacy_hmac_fallback": false
  }
}
```

The webhook-signing block is parallel to `request_signing` (inbound) and the two blocks cover the two signing directions between buyer and seller. Buyers SHOULD validate both at onboarding; a seller that signs one direction but not the other has a lopsided security posture that operators need to notice explicitly.

### extensions\_supported

Array of extension namespaces this agent supports. Buyers can expect meaningful data in `ext.{namespace}` fields on responses from this agent.

| Field                  | Type      | Description                                           |
| ---------------------- | --------- | ----------------------------------------------------- |
| `extensions_supported` | string\[] | Extension namespaces (e.g., `["iab_tcf", "iab_gpp"]`) |

Extension schemas are published in the [AdCP extension registry](/docs/building/integration/context-sessions#extensions). When an agent declares support for an extension, buyers know to look for and process `ext.{namespace}` data in responses.

**Example:**

```json theme={null}
{
  "extensions_supported": ["iab_tcf", "iab_gpp", "acmecorp"]
}
```

This tells buyers:

* Responses may include `ext.iab_tcf` with IAB TCF consent data
* Responses may include `ext.iab_gpp` with IAB GPP (Global Privacy Platform) signals
* Responses may include `ext.acmecorp` with vendor-specific data from Acme Corp

### experimental\_features

Array of experimental AdCP surfaces this agent implements. A surface is experimental when its schema carries `x-status: experimental` — it is part of the core protocol but not yet frozen and may break between 3.x releases with 6 weeks' notice. Sellers that implement any experimental surface MUST list its feature id here.

| Field                   | Type      | Description                                                                                                                                                   |
| ----------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `experimental_features` | string\[] | Experimental feature ids (e.g., `["brand.rights_lifecycle", "governance.campaign", "measurement.core", "trusted_match.core", "sponsored_intelligence.core"]`) |

Buyers should inspect `experimental_features` before relying on an experimental surface. A seller that does not list a surface is asserting it does not implement it — there is no "silently experimental" mode.

**Example:**

```json theme={null}
{
  "experimental_features": ["brand.rights_lifecycle", "measurement.core", "trusted_match.core"]
}
```

See [experimental status](/docs/reference/experimental-status) for the full stability contract, graduation criteria, and client guidance.

### wholesale\_feed\_versioning

Conditional-fetch token capabilities for [`get_products`](/docs/media-buy/task-reference/get_products#wholesale-feed-versioning) and [`get_signals`](/docs/signals/tasks/get_signals#wholesale-feed-versioning). Independent of wholesale feed webhooks: an agent MAY support cheap version probes without pushing change payloads, and an agent MAY push change payloads while still requiring reconciliation reads for repair.

| Field                      | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supported`                | boolean | **Required.** Whether the agent returns `wholesale_feed_version` on responses and honors `if_wholesale_feed_version` on requests. When absent or `false`, buyers can still probe by reading the response (the field-presence detection path) but can't pre-flight-decide which agents to cache versions for.                                                                                                                                                                                                                                                               |
| `pricing_version_separate` | boolean | Whether the agent tracks `pricing_version` independently of `wholesale_feed_version`. When `true`, callers can send `if_pricing_version` alongside `if_wholesale_feed_version` for finer-grained "did prices change?" probes. When `false` or absent, the agent collapses both into `wholesale_feed_version` — sending `if_pricing_version` is wasted bytes.                                                                                                                                                                                                               |
| `cache_scope_account`      | boolean | Whether the agent ever returns `cache_scope: "account"` (i.e., publishes per-account overlays distinct from the public rate card). When `true`, buyers MUST be prepared to maintain account-overlay caches alongside the public layer. When `false` or absent, all responses are `cache_scope: "public"` — the agent's rate card is universal across accounts. Note: declaring `true` advertises that the agent runs custom-pricing deals, which is itself a small market-posture signal; agents preferring confidentiality MAY omit the field and detect-on-call instead. |

**Example:**

```json theme={null}
{
  "wholesale_feed_versioning": {
    "supported": true,
    "pricing_version_separate": true,
    "cache_scope_account": true
  }
}
```

### wholesale\_feed\_webhooks

Per-agent wholesale product-feed and wholesale signals-feed webhook capabilities. Declared by sales agents (products) and signals agents (signals). When `supported` is `true`, consumers can register `sync_accounts.accounts[].notification_configs[]` entries for `product.*`, `signal.*`, and `wholesale_feed.bulk_change` events and receive the actual change payload in each webhook. See `specs/wholesale-feed-webhooks.md` for the full spec.

**Terminology.** Here "wholesale feed" means the agent's buyable wholesale product feed and wholesale signals feed exposed by `get_products` and `get_signals`. It is distinct from `sync_catalogs`, which pushes buyer-provided campaign input feeds into a seller account for campaign execution.

Complementary to (and independent of) [`wholesale_feed_versioning`](#wholesale_feed_versioning): webhooks push changed products/signals or bulk-change summaries; version tokens give a cheap repair and reconciliation probe. Adopters MAY ship either, both, or neither.

Agents that declare `supported: true` MUST apply the same account/caller authorization and scope predicate used by the corresponding wholesale read before emitting each webhook. A caller that could not see a product, signal, price, or account overlay through `get_products buying_mode: "wholesale"` or `get_signals discovery_mode: "wholesale"` MUST NOT receive a webhook revealing that change. Agents unable to guarantee per-principal filtering MUST NOT declare support.

**Capability consistency.** Agents listing any `product.*` value in `event_types[]` MUST declare and support wholesale `get_products` (`media_buy.buying_modes` includes `"wholesale"`). Agents listing any `signal.*` value MUST declare and support wholesale `get_signals` (`signals.discovery_modes` includes `"wholesale"`). Agents listing `wholesale_feed.bulk_change` MUST have at least one of those wholesale repair paths, and each bulk-change payload's `affected_entity_type` MUST name only a feed family the agent can repair through a declared wholesale read.

**Consumer precedence.** When more than one mechanism is declared, consumers SHOULD prefer them in this order: (1) `wholesale_feed_webhooks` when maintaining a long-lived mirror (lowest latency, lowest seller cost); (2) `wholesale_feed_versioning` conditional fetch for occasional polling and webhook repair; (3) wholesale enumeration via `buying_modes` / `discovery_modes` for cold start, `wholesale_feed.bulk_change`, or any missed/distrusted push.

| Field         | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supported`   | boolean   | **Required.** Whether this agent can push wholesale feed change payloads through account-level `sync_accounts.accounts[].notification_configs[]`. When `false` or this stanza is absent, consumers fall back to wholesale polling, optionally with `if_wholesale_feed_version` probes.                                                                                                                                                             |
| `event_types` | string\[] | Event types this agent can emit. Sales agents emit `product.*` events; signals agents emit `signal.*` events; agents that are both can emit both event families. `product.*` requires wholesale `get_products`; `signal.*` requires wholesale `get_signals`; `wholesale_feed.bulk_change` requires at least one declared wholesale repair path and names one affected feed the consumer repairs by re-reading via `get_products` or `get_signals`. |

**Example (sales + signals agent):**

```json theme={null}
{
  "wholesale_feed_webhooks": {
    "supported": true,
    "event_types": [
      "product.created", "product.updated", "product.priced", "product.removed",
      "signal.created", "signal.updated", "signal.priced", "signal.removed",
      "wholesale_feed.bulk_change"
    ]
  }
}
```

## The Capability Contract

**If a capability is declared, the seller MUST honor it.**

* `media_buy.execution.targeting.geo_postal_areas.US` contains `zip` → Buyer can send `{ country: "US", system: "zip", values: [...] }`, seller MUST honor it
* `media_buy.execution.targeting.geo_postal_areas.us_zip: true` → Buyer can send the deprecated `{ system: "us_zip", values: [...] }` form, and SDKs can backfill the native `{ country: "US", system: "zip", values: [...] }` form
* `media_buy.execution.targeting.geo_postal_areas.ZA` contains `postal_code` → Buyer can send normal South African postal codes, seller MUST honor them
* `media_buy.execution.targeting.geo_metros.nielsen_dma: true` → Buyer can send DMA codes, seller MUST honor them
* `media_buy.content_standards` object present → Seller MUST apply content standards when provided
* `media_buy.audience_targeting` object present → Seller MUST support `sync_audiences` and audience targeting overlays
* `media_buy.conversion_tracking` object present → Seller MUST support `sync_event_sources` and `log_event`
* AXE URL in `media_buy.execution.axe_integrations` → Seller can execute through that exchange (legacy — new integrations use [TMP](/docs/trusted-match))

No silent ignoring. If a seller can't support a capability, they should declare `false` or omit it.

## Common Scenarios

### Basic Capability Discovery

```javascript theme={null}
import { AdcpClient } from '@adcp/sdk';

const client = new AdcpClient({ baseUrl: 'https://seller.example.com/mcp' });

// Get seller capabilities
const result = await client.getAdcpCapabilities({});

if (result.errors) {
  throw new Error(`Request failed: ${result.errors[0].message}`);
}

// Check protocol support
console.log(`AdCP versions: ${result.adcp.major_versions.join(', ')}`);
console.log(`Supported protocols: ${result.supported_protocols.join(', ')}`);

// Check media-buy capabilities
if (result.supported_protocols.includes('media_buy')) {
  const mediaBuy = result.media_buy;

  // Check content standards support (object presence = signal)
  if (mediaBuy.content_standards) {
    console.log('Content standards supported');
  }

  // Check AXE integrations (legacy — new integrations use TMP via trusted_match on products)
  if (mediaBuy.execution?.axe_integrations?.includes('https://axe.example.com')) {
    console.log('AXE integration available');
  }

  // Check geo targeting (normalize native country keys and deprecated aliases)
  const postalSupport = mediaBuy.execution?.targeting?.geo_postal_areas;
  if (postalSupport?.US?.includes('zip') || postalSupport?.us_zip === true) {
    console.log('US ZIP code targeting supported');
  }

  // Portfolio overview
  console.log(`Publishers: ${mediaBuy.portfolio.publisher_domains.length}`);
  console.log(`Channels: ${mediaBuy.portfolio.primary_channels?.join(', ')}`);
}
```

### Check multi-protocol support

```javascript theme={null}
const caps = await client.getAdcpCapabilities({});

const sellsMedia = caps.supported_protocols.includes('media_buy');
const managesCreatives = caps.supported_protocols.includes('creative');

if (sellsMedia && managesCreatives) {
  // Single agent handles both protocols — no need to discover a separate service
  const formats = await client.listCreativeFormats({});
  const delivery = await client.getCreativeDelivery({
    media_buy_ids: ['mb_12345']
  });
}
```

### Filter sellers by capability

```javascript theme={null}
// Find sellers that support specific requirements
async function findCompatibleSellers(sellers, requirements) {
  const compatible = [];

  for (const sellerUrl of sellers) {
    const client = new AdcpClient({ baseUrl: sellerUrl });
    const caps = await client.getAdcpCapabilities({});

    if (caps.errors) continue;

    // Must support media_buy protocol
    if (!caps.supported_protocols.includes('media_buy')) continue;

    const mediaBuy = caps.media_buy;

    // Check AXE integration requirement (legacy — new integrations use TMP)
    if (requirements.axeIntegration) {
      if (!mediaBuy.execution?.axe_integrations?.includes(requirements.axeIntegration)) {
        continue;
      }
    }

    // Check geo targeting requirement
    if (requirements.postalCodeTargeting) {
      const postalSupport = mediaBuy.execution?.targeting?.geo_postal_areas;
      if (!(postalSupport?.US?.includes('zip') || postalSupport?.us_zip === true)) {
        continue;
      }
    }

    // Check content standards requirement (object presence = signal)
    if (requirements.contentStandards) {
      if (!mediaBuy.content_standards) {
        continue;
      }
    }

    compatible.push({ url: sellerUrl, capabilities: caps });
  }

  return compatible;
}

// Usage
const sellers = await findCompatibleSellers(
  ['https://seller1.com/mcp', 'https://seller2.com/mcp'],
  {
    axeIntegration: 'https://axe.example.com',
    postalCodeTargeting: true,
    contentStandards: true
  }
);
```

### Use Capabilities to Build Targeting

Capabilities tell you what you CAN specify in create\_media\_buy targeting. Use `required_geo_targeting` to filter products to sellers that support specific geo targeting levels and systems:

```javascript theme={null}
// First, check capabilities
const caps = await client.getAdcpCapabilities({});

if (!caps.supported_protocols.includes('media_buy')) {
  throw new Error('Seller does not support media_buy protocol');
}

const mediaBuy = caps.media_buy;
const postalSupport = mediaBuy.execution?.targeting?.geo_postal_areas;

// Filter products to sellers with specific geo targeting capabilities
const products = await client.getProducts({
  brief: "Premium video inventory in US for ZIP-targeted campaign",
  filters: {
    channels: ['olv', 'ctv'],
    countries: ['US'],
    // Require seller supports ZIP targeting (capability filter - no actual ZIPs needed)
    // level = granularity, system = classification taxonomy
    required_geo_targeting: [
      { level: 'postal_area', country: 'US', system: 'zip' }
    ],
    // Only include if seller supports this AXE (legacy — new integrations use TMP)
    required_axe_integrations: ['https://axe.example.com']
  }
});

// Then, create media buy with fine-grained targeting
// (if seller supports postal areas, we can target specific ZIP codes)
const buy = await client.createMediaBuy({
  brand: { domain: 'mybrand.com' },
  packages: [{
    product_id: products.products[0].product_id,
    pricing_option_id: products.products[0].pricing_options[0].id,
    budget: 10000,
    // Targeting overlay refines delivery within product coverage
    targeting_overlay: {
      geo_countries: ['US'],
      // Only specify ZIP targeting if seller supports it
      ...((postalSupport?.US?.includes('zip') || postalSupport?.us_zip === true) && {
        geo_postal_areas: [{
          country: 'US',
          system: 'zip',
          values: ['10001', '10002', '10003', '10004', '10005']
        }]
      })
    }
  }],
  start_time: { type: 'asap' },
  end_time: '2025-03-01T00:00:00Z'
});
```

**Two models for product geography:**

| Inventory Type                | Filter By                            | Example                                          |
| ----------------------------- | ------------------------------------ | ------------------------------------------------ |
| Digital (display, OLV, CTV)   | Capability: `required_geo_targeting` | Products have broad coverage, target at buy time |
| Local (radio, DOOH, local TV) | Coverage: `metros`, `regions`        | Products ARE geographically bound                |

* **Digital inventory**: Use `countries` + `required_geo_targeting` (capability), apply fine-grained targeting in `create_media_buy`
* **Local inventory**: Use `metros`/`regions` (coverage) to find products with coverage in your target markets

### Local Inventory Example (Radio, DOOH)

For locally-bound inventory, products ARE geographically specific. A radio station in NYC DMA only covers NYC.

```javascript theme={null}
// Find radio products in specific DMAs
const radioProducts = await client.getProducts({
  brief: "Radio inventory in NYC and LA markets",
  filters: {
    channels: ['radio'],
    // Coverage filter: products must cover these metros
    metros: [
      { system: 'nielsen_dma', code: '501' },  // NYC
      { system: 'nielsen_dma', code: '803' }   // LA
    ]
  }
});

// For local inventory, targeting_overlay is optional -
// the product's coverage IS the geography
const buy = await client.createMediaBuy({
  brand: { domain: 'mybrand.com' },
  packages: [{
    product_id: radioProducts.products[0].product_id,
    pricing_option_id: radioProducts.products[0].pricing_options[0].id,
    budget: 5000
    // No targeting_overlay needed - product covers NYC DMA
  }],
  start_time: { type: 'asap' },
  end_time: '2025-03-01T00:00:00Z'
});
```

## Response Example

```json theme={null}
{
  "$schema": "/schemas/protocol/get-adcp-capabilities-response.json",
  "status": "completed",
  "adcp": {
    "major_versions": [3],
    "idempotency": { "supported": true, "replay_ttl_seconds": 86400 }
  },
  "supported_protocols": ["media_buy"],
  "account": {
    "require_operator_auth": false,
    "supported_billing": ["operator", "agent"]
  },
  "media_buy": {
    "creative_approval_mode": "auto_approve",
    "features": {
      "inline_creative_management": true,
      "property_list_filtering": true
    },
    "execution": {
      "axe_integrations": ["https://axe.example.com"],
      "creative_specs": {
        "vast_versions": ["4.0", "4.1", "4.2"],
        "mraid_versions": ["3.0"],
        "vpaid": false,
        "simid": true
      },
      "targeting": {
        "geo_countries": true,
        "geo_regions": true,
        "geo_metros": {
          "nielsen_dma": true
        },
        "geo_postal_areas": {
          "us_zip": true,
          "us_zip_plus_four": true,
          "US": ["zip", "zip_plus_four"],
          "GB": ["outward", "full"],
          "CA": ["fsa", "full"],
          "ZA": ["postal_code"]
        },
        "language": true,
        "keyword_targets": {
          "supported_match_types": ["broad", "phrase", "exact"]
        },
        "negative_keywords": {
          "supported_match_types": ["broad", "exact"]
        }
      }
    },
    "content_standards": {
      "supports_local_evaluation": true,
      "supported_channels": ["display", "olv"],
      "supports_webhook_delivery": false
    },
    "audience_targeting": {
      "supported_identifier_types": ["hashed_email", "hashed_phone"],
      "supports_platform_customer_id": false,
      "supported_uid_types": ["uid2", "rampid"],
      "minimum_audience_size": 500,
      "matching_latency_hours": { "min": 1, "max": 24 }
    },
    "conversion_tracking": {
      "multi_source_event_dedup": false,
      "supported_event_types": ["purchase", "lead", "add_to_cart", "view_content"],
      "supported_action_sources": ["website", "app"],
      "attribution_windows": [
        { "post_click": [{ "interval": 7, "unit": "days" }, { "interval": 28, "unit": "days" }], "post_view": [{ "interval": 1, "unit": "days" }, { "interval": 7, "unit": "days" }] }
      ]
    },
    "portfolio": {
      "publisher_domains": ["example.com", "news.example.com"],
      "primary_channels": ["display", "olv"],
      "primary_countries": ["US", "CA"]
    }
  },
  "extensions_supported": ["acmecorp"],
  "last_updated": "2025-01-23T10:00:00Z"
}
```

This tells buyers:

* **AdCP versions**: Version 1
* **Protocols**: Media buy only
* **Auth model**: Agent-trusted (`require_operator_auth: false`) — authenticate once, declare brands via `sync_accounts`
* **Billing**: Operator or agent billing; default is operator
* **Country targeting**: Available (ISO 3166-1 alpha-2: `US`, `GB`, etc.)
* **Region targeting**: Available (ISO 3166-2: `US-NY`, `GB-SCT`, etc.)
* **Metro targeting**: Nielsen DMA only (US market)
* **Postal targeting**: US ZIP, UK outward codes, Canadian FSA
* **Audience targeting**: Accepts hashed email, hashed phone, UID2, and RampID; minimum matched audience size of 500; matching latency 1–24 hours
* **Conversion tracking**: Accepts purchase, lead, add\_to\_cart, view\_content events from website/app; no multi-source dedup
* **Extensions**: Vendor-specific data in `ext.acmecorp`

### Multi-protocol agent

An agent can implement multiple protocols from a single endpoint. This is common for sellers that manage both media buying and creative generation — the buyer calls all tasks on the same URL.

```json theme={null}
{
  "$schema": "/schemas/protocol/get-adcp-capabilities-response.json",
  "status": "completed",
  "adcp": {
    "major_versions": [3],
    "idempotency": { "supported": true, "replay_ttl_seconds": 86400 }
  },
  "supported_protocols": ["media_buy", "creative"],
  "account": {
    "require_operator_auth": false,
    "supported_billing": ["operator"]
  },
  "media_buy": {
    "creative_approval_mode": "require_human",
    "features": {
      "inline_creative_management": true
    },
    "portfolio": {
      "publisher_domains": ["news.example.com"],
      "primary_channels": ["display", "olv"]
    }
  },
  "creative": {
    "has_creative_library": true,
    "supports_generation": true,
    "supports_transformation": false,
    "supports_compliance": false,
    "bills_through_adcp": true
  }
}
```

This agent supports:

* **Media Buy Protocol**: Product discovery, media buying, delivery reporting
* **Creative Protocol**: Creative library management, AI-powered creative generation, variant-level delivery analytics via `get_creative_delivery`
* **Shared account**: A single account established via `sync_accounts` applies to both protocols

When `supported_protocols` includes `"creative"`, the buyer can call Creative Protocol tasks (`list_creative_formats`, `sync_creatives`, `get_creative_delivery`, etc.) on this agent. See [Creative capabilities on sales agents](/docs/creative/sales-agent-creative-capabilities).

### Geo Standards Reference

| Level       | System                 | Examples                                 |
| ----------- | ---------------------- | ---------------------------------------- |
| Country     | ISO 3166-1 alpha-2     | `US`, `GB`, `DE`, `CA`                   |
| Region      | ISO 3166-2             | `US-NY`, `GB-SCT`, `DE-BY`, `CA-ON`      |
| Metro (US)  | `nielsen_dma`          | `501` (NYC), `803` (LA), `602` (Chicago) |
| Metro (UK)  | `uk_itl2`              | `UKI` (London), `UKD` (North West)       |
| Metro (EU)  | `eurostat_nuts2`       | `DE30` (Berlin), `FR10` (Île-de-France)  |
| Postal (US) | `US` / `zip`           | `10001`, `90210`                         |
| Postal (US) | `US` / `zip_plus_four` | `10001-1234`                             |
| Postal (UK) | `GB` / `outward`       | `SW1`, `EC1`, `M1`                       |
| Postal (UK) | `GB` / `full`          | `SW1A 1AA`                               |
| Postal (CA) | `CA` / `fsa`           | `K1A`, `M5V`                             |

## Migration from list\_authorized\_properties (v2)

The `list_authorized_properties` task was removed in v3. If migrating from v2:

| Old Field               | New Location                               |
| ----------------------- | ------------------------------------------ |
| `publisher_domains`     | `media_buy.portfolio.publisher_domains`    |
| `primary_channels`      | `media_buy.portfolio.primary_channels`     |
| `primary_countries`     | `media_buy.portfolio.primary_countries`    |
| `portfolio_description` | `media_buy.portfolio.description`          |
| `advertising_policies`  | `media_buy.portfolio.advertising_policies` |
| `last_updated`          | `last_updated` (top level)                 |

New fields:

* `adcp.major_versions` - Version compatibility
* `supported_protocols` - Which domain protocols are supported
* `media_buy.features` - Optional feature support
* `media_buy.execution.axe_integrations` - Ad exchange support
* `media_buy.execution.creative_specs` - VAST/MRAID versions
* `media_buy.execution.targeting` - Geo targeting granularity

## Error Handling

| Error Code            | Description                                                    | Resolution                                                                   |
| --------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `AUTH_MISSING`        | No credentials presented                                       | Provide credentials via auth header                                          |
| `AUTH_INVALID`        | Credentials rejected (expired / revoked)                       | Human credential rotation required                                           |
| `VERSION_UNSUPPORTED` | Declared `adcp_major_version` not in seller's `major_versions` | Call without `adcp_major_version` to discover supported versions, then retry |
| `INTERNAL_ERROR`      | Server error                                                   | Retry with backoff                                                           |

## Best Practices

**1. Cache Capabilities**
Capabilities rarely change. Cache results and use `last_updated` for staleness detection.

**2. Check Protocol Support First**
Before accessing protocol-specific fields, verify the protocol is in `supported_protocols`.

**3. Check Before Requesting**
Don't send postal areas for a system the seller doesn't support. Don't request features the seller doesn't support.

**4. Fail Fast on Incompatibility**
If a seller doesn't support required capabilities, skip them early rather than discovering failures later.

**5. Read the Auth Model Before Proceeding**
Check `account.require_operator_auth` immediately after discovery. Agent-trusted and operator-scoped flows diverge significantly: the former uses a single credential for all brands and operators, the latter requires per-operator credentials and sessions.

**6. Use Protocol Version for Routing**
Route requests to appropriate API versions based on `adcp.major_versions`.

## Next Steps

After discovering capabilities:

1. **Set up accounts**: Follow the auth model from `account.require_operator_auth` — see [Accounts and Agents](/docs/building/integration/accounts-and-agents#what-sellers-declare)
2. **Filter products**: Use [`get_products`](/docs/media-buy/task-reference/get_products) with capability-aware filters
3. **Validate properties**: Fetch publisher `adagents.json` files for property definitions
4. **Create buys**: Use [`create_media_buy`](/docs/media-buy/task-reference/create_media_buy) with supported features

## Learn More

* [Accounts and Agents](/docs/building/integration/accounts-and-agents) - Auth models, account setup, billing
* [adagents.json Specification](/docs/governance/property/adagents) - Publisher authorization files
* [Product Filters](/docs/media-buy/task-reference/get_products#filters) - Capability-aware filtering
* [Content Standards](/docs/governance/content-standards) - Brand safety configuration
