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

# Compliance Catalog

> Full index of AdCP protocols and specialisms an agent can claim — what each one means, which compliance storyboards run, and where to find the source YAML.

Every AdCP agent declares its `supported_protocols` and `specialisms` in [`get_adcp_capabilities`](/dist/docs/3.2.0-beta.10/protocol/get_adcp_capabilities). Each declaration maps to a compliance bundle at `/compliance/{version}/` that the storyboard runner executes to verify the claim.

<Note>
  **`supported_protocols` is not exhaustive.** The `accounts` surface ([`sync_accounts`](/dist/docs/3.2.0-beta.10/accounts/tasks/sync_accounts), [`list_accounts`](/dist/docs/3.2.0-beta.10/accounts/tasks/list_accounts), [`sync_governance`](/dist/docs/3.2.0-beta.10/accounts/tasks/sync_governance)) is a foundation implicit in every `media_buy`, `creative`, and `signals` agent and is intentionally not a `supported_protocols` value. See [Accounts tasks](/dist/docs/3.2.0-beta.10/accounts/tasks/sync_accounts) for the full account surface.
</Note>

This page is the human-readable index of that taxonomy. The machine-readable equivalent is `/compliance/{version}/index.json`.

## Universal storyboards

Every agent runs every graded storyboard in `/compliance/{version}/universal/` regardless of which protocols or specialisms it claims. A few are *capability-gated* — they only run when the agent advertises the relevant capability — but the storyboard is still universal in scope: any agent claiming the capability is graded by it. Failing a universal storyboard fails overall compliance. Non-executable schemas and support fixtures shipped in the universal bundle are not runner scenarios and do not appear in this table.

| Graded storyboard                         | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | Source                                                                                                         |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `account-identity-reconciliation`         | Validates revision-guarded operator identity rekeying, collision safety, and former-key redirects for sellers that advertise identity updates.                                                                                                                                                                                                                                                                                                                                                                                                                              | [YAML](https://adcontextprotocol.org/compliance/latest/universal/account-identity-reconciliation.yaml)         |
| `agent-notification-configs`              | Validates the 3.2 agent-level capabilities.changed registration surface: advertised revision fencing, NO\_AUTH rejection, and dry-run clear semantics.                                                                                                                                                                                                                                                                                                                                                                                                                      | [YAML](https://adcontextprotocol.org/compliance/latest/universal/agent-notification-configs.yaml)              |
| `billing-gate-dispatch`                   | Validates that account.supported\_billing is declared and honored by sync\_accounts, including out-of-set BILLING\_NOT\_SUPPORTED rejection, recovery-value consistency, and the distinct per-buyer-agent BILLING\_NOT\_PERMITTED\_FOR\_AGENT gate.                                                                                                                                                                                                                                                                                                                         | [YAML](https://adcontextprotocol.org/compliance/latest/universal/billing-gate-dispatch.yaml)                   |
| `canonical-format-validate-input`         | Validates 3.1 canonical-format dry-run semantics: structural pass/fail across canonical slots and unvalidatable\_nondeterministic for seeded products.                                                                                                                                                                                                                                                                                                                                                                                                                      | [YAML](https://adcontextprotocol.org/compliance/latest/universal/canonical-format-validate-input.yaml)         |
| `capability-discovery`                    | Buyer calls get\_adcp\_capabilities to discover what an agent supports before making any buying or creative decisions.                                                                                                                                                                                                                                                                                                                                                                                                                                                      | [YAML](https://adcontextprotocol.org/compliance/latest/universal/capability-discovery.yaml)                    |
| `collection-lists-pagination-integrity`   | Validates the cursor↔has\_more invariant by walking a paginated list\_collection\_lists response from a continuation page to a terminal page.                                                                                                                                                                                                                                                                                                                                                                                                                               | [YAML](https://adcontextprotocol.org/compliance/latest/universal/collection-lists-pagination-integrity.yaml)   |
| `comply-controller-mode-gate`             | Verifies that a seller exposing comply\_test\_controller refuses calls from live-mode (non-sandbox) accounts with FORBIDDEN.                                                                                                                                                                                                                                                                                                                                                                                                                                                | [YAML](https://adcontextprotocol.org/compliance/latest/universal/comply-controller-mode-gate.yaml)             |
| `content-standards-pagination-integrity`  | Validates the cursor↔has\_more invariant by walking a paginated list\_content\_standards response from a continuation page to a terminal page.                                                                                                                                                                                                                                                                                                                                                                                                                              | [YAML](https://adcontextprotocol.org/compliance/latest/universal/content-standards-pagination-integrity.yaml)  |
| `ctv-experience-validate-input`           | Validates AdCP 3.2 ctv\_ad\_experience matrix pairings, duration/interactivity constraint profiles, the menu focus/video pairing, and non-blocking activation-copy warnings via validate\_input against seeded CTV products.                                                                                                                                                                                                                                                                                                                                                | [YAML](https://adcontextprotocol.org/compliance/latest/universal/ctv-experience-validate-input.yaml)           |
| `deterministic-testing`                   | Uses comply\_test\_controller to force state transitions and simulate delivery/budget, verifying state machines and reporting.                                                                                                                                                                                                                                                                                                                                                                                                                                              | [YAML](https://adcontextprotocol.org/compliance/latest/universal/deterministic-testing.yaml)                   |
| `error-compliance`                        | Validates that agents return properly structured AdCP errors with correct codes, recovery hints, and transport bindings.                                                                                                                                                                                                                                                                                                                                                                                                                                                    | [YAML](https://adcontextprotocol.org/compliance/latest/universal/error-compliance.yaml)                        |
| `error-compliance-signals`                | Validates that signals agents return properly structured AdCP errors with correct codes, recovery hints, and transport bindings.                                                                                                                                                                                                                                                                                                                                                                                                                                            | [YAML](https://adcontextprotocol.org/compliance/latest/universal/error-compliance-signals.yaml)                |
| `get-media-buys-pagination-integrity`     | Validates that get\_media\_buys responses carry a well-formed pagination envelope honoring the cursor↔has\_more invariant.                                                                                                                                                                                                                                                                                                                                                                                                                                                  | [YAML](https://adcontextprotocol.org/compliance/latest/universal/get-media-buys-pagination-integrity.yaml)     |
| `get-products-pagination-integrity`       | Validates get\_products wholesale-mode pagination by walking a seeded product feed from continuation to terminal, while documenting that brief/refine pagination caps returned products in curated results.                                                                                                                                                                                                                                                                                                                                                                 | [YAML](https://adcontextprotocol.org/compliance/latest/universal/get-products-pagination-integrity.yaml)       |
| `get-signals-pagination-integrity`        | Validates the cursor↔has\_more invariant on a paginated get\_signals response by walking from a continuation page to the next page under a broad query.                                                                                                                                                                                                                                                                                                                                                                                                                     | [YAML](https://adcontextprotocol.org/compliance/latest/universal/get-signals-pagination-integrity.yaml)        |
| `idempotency`                             | Validates that mutating requests enforce idempotency\_key — replays return cached responses, key reuse with a different payload returns IDEMPOTENCY\_CONFLICT, fresh keys create new resources, and concurrent retries with the same key produce exactly one resource (first-insert-wins under rule 9).                                                                                                                                                                                                                                                                     | [YAML](https://adcontextprotocol.org/compliance/latest/universal/idempotency.yaml)                             |
| `notification-config-event-scope`         | Validates that sync\_accounts.accounts\[].notification\_configs\[] rejects media-buy-anchored notification types.                                                                                                                                                                                                                                                                                                                                                                                                                                                           | [YAML](https://adcontextprotocol.org/compliance/latest/universal/notification-config-event-scope.yaml)         |
| `notification-config-lifecycle`           | Validates account-level notification\_configs\[] lifecycle behavior on sync\_accounts: paused registration, durable echo, subscriber-keyed replacement, and clear.                                                                                                                                                                                                                                                                                                                                                                                                          | [YAML](https://adcontextprotocol.org/compliance/latest/universal/notification-config-lifecycle.yaml)           |
| `notification-config-rejections`          | Validates account-level notification\_configs\[] semantic rejection for duplicate subscriber keys.                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | [YAML](https://adcontextprotocol.org/compliance/latest/universal/notification-config-rejections.yaml)          |
| `oauth-setup`                             | Capability-gated evaluation of an agent's RFC 9728 protected-resource metadata and the complete RFC 8414 authorization-server graph it advertises.                                                                                                                                                                                                                                                                                                                                                                                                                          | [YAML](https://adcontextprotocol.org/compliance/latest/universal/oauth-setup.yaml)                             |
| `pagination-integrity`                    | Validates the cursor↔has\_more invariant by walking a paginated list\_creatives response from a continuation page to a terminal page.                                                                                                                                                                                                                                                                                                                                                                                                                                       | [YAML](https://adcontextprotocol.org/compliance/latest/universal/pagination-integrity.yaml)                    |
| `pagination-integrity-creative-formats`   | When an agent still exposes deprecated list\_creative\_formats compatibility, validates its cursor↔has\_more invariant by seeding two formats and walking pages with max\_results=1.                                                                                                                                                                                                                                                                                                                                                                                        | [YAML](https://adcontextprotocol.org/compliance/latest/universal/pagination-integrity-creative-formats.yaml)   |
| `pagination-integrity-list-accounts`      | Validates list\_accounts pagination by seeding sandbox accounts, requesting a small first page, and following its cursor once.                                                                                                                                                                                                                                                                                                                                                                                                                                              | [YAML](https://adcontextprotocol.org/compliance/latest/universal/pagination-integrity-list-accounts.yaml)      |
| `premium-display-canonical-validation`    | Validates AdCP 3.2 seller\_rendered\_stateful\_display supply-mode contracts (components, rendered\_canvases, layered\_source), single-state reveal shape, policy floors, and coordinated\_placements sequence/serving\_policy, alongside transition/canvas coverage and shared-slot resolution.                                                                                                                                                                                                                                                                            | [YAML](https://adcontextprotocol.org/compliance/latest/universal/premium-display-canonical-validation.yaml)    |
| `principal`                               | Validates the experimental stable-principal-scoped configuration surface: capability discovery, pre-configuration identity readback, NO\_AUTH rejection, dry-run setup, applied lifecycle with readback, idempotent replay, and section clearing.                                                                                                                                                                                                                                                                                                                           | [YAML](https://adcontextprotocol.org/compliance/latest/universal/principal.yaml)                               |
| `property-lists-pagination-integrity`     | Validates the cursor↔has\_more invariant by walking a paginated list\_property\_lists response from a continuation page to a terminal page.                                                                                                                                                                                                                                                                                                                                                                                                                                 | [YAML](https://adcontextprotocol.org/compliance/latest/universal/property-lists-pagination-integrity.yaml)     |
| `read-tool-idempotency`                   | Validates that read-only AdCP tasks and the 3.x get\_products compatibility facade accept an optional idempotency\_key without strict wrapper rejection.                                                                                                                                                                                                                                                                                                                                                                                                                    | [YAML](https://adcontextprotocol.org/compliance/latest/universal/read-tool-idempotency.yaml)                   |
| `reporting-core`                          | Validates the required reporting.core tier: capability declaration with tier boundaries, and that a polling-only seller needs no receipt task, push notification, destination, or canonicalization surface.                                                                                                                                                                                                                                                                                                                                                                 | [YAML](https://adcontextprotocol.org/compliance/latest/universal/reporting-core.yaml)                          |
| `schema-validation`                       | Validates that agent responses conform to AdCP schemas and that temporal constraints are enforced.                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | [YAML](https://adcontextprotocol.org/compliance/latest/universal/schema-validation.yaml)                       |
| `schema-validation-signals`               | Validates that signals agent responses conform to AdCP schemas with all required fields present and correctly typed.                                                                                                                                                                                                                                                                                                                                                                                                                                                        | [YAML](https://adcontextprotocol.org/compliance/latest/universal/schema-validation-signals.yaml)               |
| `security`                                | Every AdCP agent MUST require authentication on protected operations. At least one of static credentials or OAuth MUST be implemented and correctly advertised.                                                                                                                                                                                                                                                                                                                                                                                                             | [YAML](https://adcontextprotocol.org/compliance/latest/universal/security.yaml)                                |
| `signed-requests`                         | Agent verifies RFC 9421 HTTP Signatures on incoming AdCP requests per the 3.1-compatible transport-layer profile. Universal capability-gated storyboard — runs for any agent advertising <code>{"request_signing.supported: true"}</code> regardless of <code>{"supported_protocols"}</code>. Graded against the legacy wire suite covering every 3.1 checklist step and canonicalization-edge rule.                                                                                                                                                                        | [YAML](https://adcontextprotocol.org/compliance/latest/universal/signed-requests.yaml)                         |
| `stale-response-advisory`                 | Validates that STALE\_RESPONSE rides in errors\[] on a populated success response with transport success preserved, and that STALE\_RESPONSE is absent on healthy upstream responses.                                                                                                                                                                                                                                                                                                                                                                                       | [YAML](https://adcontextprotocol.org/compliance/latest/universal/stale-response-advisory.yaml)                 |
| `trusted-match-publisher-authentication`  | Verifies that a TMP router deployment rejects schema-valid Context Match and Identity Match requests with absent or invalid publisher authentication using HTTP 401 and a WWW-Authenticate challenge.                                                                                                                                                                                                                                                                                                                                                                       | [YAML](https://adcontextprotocol.org/compliance/latest/universal/trusted-match-publisher-authentication.yaml)  |
| `v3-envelope-integrity`                   | v3 protocol envelopes MUST NOT carry task\_status or response\_status — v2 legacy field names that have no semantics in v3.                                                                                                                                                                                                                                                                                                                                                                                                                                                 | [YAML](https://adcontextprotocol.org/compliance/latest/universal/v3-envelope-integrity.yaml)                   |
| `version-negotiation`                     | Sellers advertise supported releases on capabilities and echo the served release on every response.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | [YAML](https://adcontextprotocol.org/compliance/latest/universal/version-negotiation.yaml)                     |
| `webhook-emission`                        | Any agent that emits webhooks MUST echo the caller-supplied operation\_id in every payload, carry a stable idempotency\_key across retries, avoid duplicate webhook side effects on request replay, and — when the buyer has not opted into the deprecated HMAC fallback — MUST sign deliveries under the RFC 9421 webhook profile. Sellers MUST NOT emit task webhooks for inline terminal responses; any future sync-completion notification mode would be explicit and capability-advertised. Graded by a runner hosting a webhook receiver during storyboard execution. | [YAML](https://adcontextprotocol.org/compliance/latest/universal/webhook-emission.yaml)                        |
| `webhook-receiver-envelope`               | Buyer webhook receivers MUST accept full MCP webhook envelopes, reject bare delivery-result payloads, preserve raw-body signature verification, and dedupe retries by a stable idempotency\_key.                                                                                                                                                                                                                                                                                                                                                                            | [YAML](https://adcontextprotocol.org/compliance/latest/universal/webhook-receiver-envelope.yaml)               |
| `wholesale-feed-bulk-webhooks`            | Validates account-level notification\_configs\[] registration for agents that advertise wholesale\_feed.bulk\_change webhook events.                                                                                                                                                                                                                                                                                                                                                                                                                                        | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-bulk-webhooks.yaml)            |
| `wholesale-feed-product-webhooks`         | Validates account-level notification\_configs\[] registration for agents that advertise product wholesale feed webhook events.                                                                                                                                                                                                                                                                                                                                                                                                                                              | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-product-webhooks.yaml)         |
| `wholesale-feed-products`                 | Validates get\_products wholesale feed versioning: bootstrap responses carry wholesale\_feed\_version/cache\_scope and matching if\_wholesale\_feed\_version probes return unchanged without product rows.                                                                                                                                                                                                                                                                                                                                                                  | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-products.yaml)                 |
| `wholesale-feed-products-scope-isolation` | Validates that get\_products conditional-fetch is keyed by cache\_scope: a wholesale\_feed\_version minted under one cache\_scope must not short-circuit (unchanged: true) a request the seller resolves to a different cache\_scope.                                                                                                                                                                                                                                                                                                                                       | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-products-scope-isolation.yaml) |
| `wholesale-feed-signal-webhooks`          | Validates account-level notification\_configs\[] registration for agents that advertise signal wholesale feed webhook events.                                                                                                                                                                                                                                                                                                                                                                                                                                               | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-signal-webhooks.yaml)          |
| `wholesale-feed-signals`                  | Validates get\_signals wholesale feed versioning: bootstrap responses carry wholesale\_feed\_version/cache\_scope and matching if\_wholesale\_feed\_version probes return unchanged without signal rows.                                                                                                                                                                                                                                                                                                                                                                    | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-signals.yaml)                  |
| `wholesale-feed-signals-scope-isolation`  | Validates that get\_signals conditional-fetch is keyed by cache\_scope: a wholesale\_feed\_version minted under one cache\_scope must not short-circuit (unchanged: true) a request the agent resolves to a different cache\_scope.                                                                                                                                                                                                                                                                                                                                         | [YAML](https://adcontextprotocol.org/compliance/latest/universal/wholesale-feed-signals-scope-isolation.yaml)  |

Capability-gated rows (`deterministic-testing`, `oauth-setup`, `signed-requests`) are skipped when the corresponding capability is absent or advertises `supported: false`; they cannot be claimed and partially implemented. Declaring `supported: true` and failing the storyboard is non-conformant — omit the capability or declare `false` rather than ship a partial implementation. The `billing-gate-dispatch` and `comply-controller-mode-gate` rows are precondition-gated rather than ordinary capability-gated rows: each phase grades `not_applicable` when its precondition is not met. Sellers wanting full coverage of the per-agent billing gate SHOULD ship a test kit with `commercial_relationship: passthrough_only` declared so the per-agent phases run.

## Standard error codes

The compliance suite verifies that standard errors use the recovery classifications and remediation guidance defined by the canonical [`error-code.json`](https://github.com/adcontextprotocol/adcp/blob/main/static/schemas/source/enums/error-code.json) source taxonomy. The vocabulary remains open: agents must also handle unknown codes using the response's `recovery` value.

| Code                                     | Recovery    | Suggested action                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ---------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ACCOUNT_AMBIGUOUS`                      | correctable | pass explicit account\_id or a more specific natural key                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `ACCOUNT_IDENTITY_CONFLICT`              | correctable | choose a different operator or operator\_unit identity, or retain the account's current identity; do not retry the same desired identity unchanged                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `ACCOUNT_MOVED`                          | correctable | replace the stale reference with error.details.current\_account, refresh through list\_accounts, and retry with a fresh idempotency key                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `ACCOUNT_NOT_FOUND`                      | terminal    | verify account via list\_accounts or contact seller                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `ACCOUNT_PAYMENT_REQUIRED`               | terminal    | buyer must resolve billing                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `ACCOUNT_REQUIRED`                       | correctable | pass account, or reference an existing resource whose owning account the service can resolve                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `ACCOUNT_SETUP_REQUIRED`                 | correctable | check details.setup for URL or instructions                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `ACCOUNT_SUSPENDED`                      | terminal    | contact seller to resolve suspension                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `ACTION_NOT_ALLOWED`                     | correctable | branch on error.details.reason: for wrong\_status, wait for or transition to a status listed under the action's allowed\_statuses; for mode\_mismatch, this is a flow switch (not a retry against update\_media\_buy) — follow the mode named in available\_actions\[\<action>].mode; for condition\_unresolved, wait until the seller advertises the action after resolving its opaque condition; for not\_supported\_on\_product or not\_supported\_on\_buy, do not retry — the action is unavailable on this buy and buyer must select a different product or renegotiate |
| `AGENT_BLOCKED`                          | terminal    | surface to a human at the buyer — the relationship is permanently denied and is reinstated only through offline operator action with the seller, not via any seller-callable AdCP task                                                                                                                                                                                                                                                                                                                                                                                       |
| `AGENT_SUSPENDED`                        | terminal    | surface to a human at the buyer — the agent cannot unilaterally lift a suspension; re-onboarding with the seller offline may resolve                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `AMBIGUOUS_BIDDING_POLICY`               | correctable | remove either the canonical bidding block or all legacy bidding fields from the effective package                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `AUDIENCE_TOO_SMALL`                     | correctable | broaden targeting or upload more audience members                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `AUTHORIZATION_REQUIRED`                 | correctable | complete or restore the required downstream platform connection, identity, creator, or post authorization; use error.details.missing\_connections, authorization\_url, authorization\_instructions, or reference\_authorization when present                                                                                                                                                                                                                                                                                                                                 |
| `AUTH_INVALID`                           | terminal    | do NOT auto-retry — credentials were rejected; rotate keys, refresh OAuth tokens once if applicable, otherwise escalate to a human                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `AUTH_MISSING`                           | correctable | provide credentials via the auth header and retry                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `AUTH_REQUIRED`                          | correctable | provide credentials when missing; do NOT auto-retry rejected credentials — escalate for rotation                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `BIDDING_PLACEMENT_CONFLICT`             | correctable | align media-buy and package bidding scopes with the provider's supported placement, or choose a compatible budget mode/product combination                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `BILLING_NOT_PERMITTED_FOR_AGENT`        | correctable | retry with error.details.suggested\_billing (typically 'operator') when present; when absent, surface to a human at the buyer — the agent cannot unilaterally extend its commercial relationship and MUST NOT auto-retry                                                                                                                                                                                                                                                                                                                                                     |
| `BILLING_NOT_SUPPORTED`                  | correctable | check get\_adcp\_capabilities for supported\_billing and resubmit with a supported value, or omit billing to accept the seller's default                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `BILLING_OUT_OF_BAND`                    | terminal    | do not retry — billing for this account runs through a non-AdCP channel. Pre-filter via capabilities.creative.bills\_through\_adcp before sending report\_usage; flag the account in the buyer's routing table and fall back to the ad server's native billing export for cost reconciliation                                                                                                                                                                                                                                                                                |
| `BRAND_REQUIRED`                         | correctable | include brand (domain plus optional brand\_id) on the request                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `BUDGET_CAP_REACHED`                     | correctable | raise max\_spend, or reduce max\_creatives/max\_variants, to produce the remaining items                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `BUDGET_EXCEEDED`                        | correctable | reduce requested amount or increase budget allocation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `BUDGET_EXHAUSTED`                       | terminal    | buyer must add funds or increase budget cap                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `BUDGET_TOO_LOW`                         | correctable | increase budget or check capabilities.media\_buy.limits                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `CAMPAIGN_SUSPENDED`                     | transient   | wait for the escalation to resolve; contact the plan operator if the suspension persists                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `CATALOG_LIMIT_EXCEEDED`                 | correctable | remove unused catalogs, or contact the seller to raise the limit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `COMPLIANCE_UNSATISFIED`                 | correctable | choose a format that supports the required disclosure positions and persistence modes, or remove the disclosure requirement                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `CONFIGURATION_ERROR`                    | terminal    | surface to a human at the seller — the buyer cannot resolve a seller-side deployment misconfiguration and MUST NOT auto-retry                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `CONFLICT`                               | transient   | re-read the resource and retry with current state                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `CONFLICTING_SELECTORS`                  | correctable | emit one canonical format selector route, or make every required legacy 3.x compatibility projection select the same product format contract under the canonical v2-narrows-v1 comparison                                                                                                                                                                                                                                                                                                                                                                                    |
| `CREATIVE_DEADLINE_EXCEEDED`             | correctable | check creative\_deadline via get\_media\_buys before submitting changes, or negotiate a deadline extension with the seller                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `CREATIVE_INACCESSIBLE`                  | correctable | verify the asset URLs in creative\_manifest are reachable without agent-side credentials, then re-submit                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `CREATIVE_LOCALE_NOT_ACCEPTED`           | correctable | supply or assign a creative variant matching every in-scope format option's accepted\_language\_ranges, narrow placement scope, choose a compatible format option, or change an ineligible serve\_default                                                                                                                                                                                                                                                                                                                                                                    |
| `CREATIVE_MISSING_CLICK_URL`             | correctable | add the required destination URL and resubmit the creative                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `CREATIVE_NOT_FOUND`                     | correctable | verify creative\_id via list\_creatives, or sync\_creatives to register it                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `CREATIVE_REJECTED`                      | correctable | revise the creative according to the applicable advertising policy or validated accessibility criteria                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `CREATIVE_REPRESENTATION_UNRESOLVED`     | correctable | inspect every error.details.representation\_rejections entry, then choose a compatible format option or supply a compatible representation                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `CREATIVE_REVISION_CONTENT_MISMATCH`     | correctable | resend the exact content previously bound to this revision\_id, or mint a new revision\_id for changed content                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `CREATIVE_SIZE_MISMATCH`                 | correctable | resize or replace the creative with a size accepted by every selected package that may serve it                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `CREATIVE_VALIDATION_FAILED_GENERIC`     | correctable | correct the buyer-visible validation problem and resubmit the creative                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `CREATIVE_VALUE_NOT_ALLOWED`             | correctable | pick a value from error.details.allowed\_values (or re-fetch the format) and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `CREDENTIAL_IN_ARGS`                     | terminal    | do NOT auto-retry — auto-retry re-logs the credential on each attempt. Move authentication material or caller-supplied trust material out of request args (top-level, <code>{"context"}</code>, <code>{"ext"}</code>, any nested location) onto the relevant transport authentication/trust channel or account provisioning path (Authorization: Bearer, RFC 9421 signature/JWKS, mTLS, MCP/A2A authentication framing); rotate any leaked credential, then resubmit                                                                                                         |
| `CURSOR_EXPIRED`                         | correctable | obtain a latest checkpoint, rebuild authoritative account snapshots, then drain changes after the checkpoint                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `EVALUATOR_AGENT_NOT_ACCEPTED`           | correctable | replace the evaluator agent\_url (evaluator.feature\_agent.agent\_url or the evaluator agent-form agent\_url) with one from the seller's published accepted\_verifiers, or drop the evaluator agent pointer to fall back to seller-default ranking                                                                                                                                                                                                                                                                                                                           |
| `FEED_FETCH_FAILED`                      | correctable | check URL accessibility, authentication, and that content matches the declared feed\_format                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `FIELD_NOT_PERMITTED`                    | correctable | drop the disallowed field(s) and retry                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `FORMAT_DECLARATION_DIVERGENT`           | correctable | advisory — seller-side fix needed: producer is emitting disagreeing format\_ids and format\_options for the same product. Buyer SDK SHOULD prefer format\_options and surface the divergent product to operators; do not auto-retry                                                                                                                                                                                                                                                                                                                                          |
| `FORMAT_DECLARATION_V1_AMBIGUOUS`        | correctable | advisory — seller-side fix needed: the v2 declaration's canonical has only family-level structural registry entries (no invertible literal). Seller MUST author v1\_format\_ref on the v2 declaration to disambiguate; SDKs MUST NOT synthesize. Do not auto-retry                                                                                                                                                                                                                                                                                                           |
| `FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE` | correctable | advisory — emitted alongside the partial v1 emission, NOT in place of it: the v2 declaration carries <code>{"params.sizes[]"}</code> with N entries but only M v1\_format\_ref entries (M \< N), so v1 buyers see partial size coverage on the product. Seller-side fix: add v1\_format\_ref entries for the missing sizes. SDK MAY (non-normative) fan out automatically by catalog lookup. Non-fatal — do not auto-retry                                                                                                                                                   |
| `FORMAT_NOT_SUPPORTED`                   | correctable | refresh get\_adcp\_capabilities creative.supported\_formats\[] and retry with a capability\_id whose operations contains the intended build, preview, or validate operation                                                                                                                                                                                                                                                                                                                                                                                                  |
| `FORMAT_OPTION_UNRESOLVED`               | correctable | advisory — publisher-side fix needed: a placement's <code>{"format_options[].format_option_id"}</code> references a <code>{"format_option_id"}</code> that does not exist in this file's top-level <code>{"formats[]"}</code>. Buyer SDK MUST fail closed for that placement (drop the format from the placement's accepted set) and surface this code. Publisher fix: either declare the missing format option in <code>{"formats[]"}</code> or remove the reference from the placement. Do not auto-retry                                                                  |
| `FORMAT_PROJECTION_FAILED`               | correctable | advisory — seller-side fix needed: ask the seller to add an explicit <code>{"canonical"}</code> field on the legacy format declaration, or contribute a registry entry (format\_id\_glob or structural match) to v1-canonical-mapping.json. Do not auto-retry; the product is still valid on the legacy named-format path                                                                                                                                                                                                                                                    |
| `FORMAT_SHAPE_PROMOTED`                  | correctable | advisory — migrate the legacy custom format\_shape to error.details.promoted\_to before error.details.transition\_end; dual emission is allowed during the transition window. Do not auto-retry                                                                                                                                                                                                                                                                                                                                                                              |
| `GOVERNANCE_AGENT_NOT_ACCEPTED`          | correctable | select a governance agent matching <code>{"error.details.accepted_governance_agents"}</code>, then retry <code>{"sync_governance"}</code> with a fresh idempotency key                                                                                                                                                                                                                                                                                                                                                                                                       |
| `GOVERNANCE_DENIED`                      | correctable | restructure the buy, escalate to human spending authority, or contact the governance agent for details                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `GOVERNANCE_UNAVAILABLE`                 | transient   | retry with backoff; if the agent remains unreachable, the buyer MUST contact the plan's governance operator                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `IDEMPOTENCY_CONFLICT`                   | correctable | use a fresh UUID v4 for the new request, or resend the exact original payload to get the cached response                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `IDEMPOTENCY_EXPIRED`                    | correctable | perform a natural-key check to determine whether the original request succeeded; if no evidence of success, generate a fresh idempotency\_key for a new attempt                                                                                                                                                                                                                                                                                                                                                                                                              |
| `IDEMPOTENCY_IN_FLIGHT`                  | transient   | wait top-level error.retry\_after seconds and retry with the SAME idempotency\_key — MUST NOT mint a fresh key (turns a safe retry into a double-execution race)                                                                                                                                                                                                                                                                                                                                                                                                             |
| `INVALID_FEED_FORMAT`                    | correctable | verify the feed content matches the declared format                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `INVALID_PRICING_OPTION`                 | correctable | verify pricing\_option\_id against the product's pricing\_options from get\_products or the vendor's discovery response, then resubmit with a valid ID                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `INVALID_REQUEST`                        | correctable | check request parameters and fix                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `INVALID_STATE`                          | correctable | check current status via get\_media\_buys and adjust request                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `INVALID_USAGE_DATA`                     | correctable | check required fields for the vendor type (vendor\_cost, currency, account at minimum), fix invalid values, and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `IO_REQUIRED`                            | correctable | review the proposal's insertion\_order, accept terms, and include io\_acceptance on accept\_proposal; use create\_media\_buy only for 3.x compatibility                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `ITEM_VALIDATION_FAILED`                 | correctable | check item\_issues for per-item rejection reasons and fix the offending items                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `MACRO_RESOLUTION_FAILED`                | correctable | inspect error.details.macro\_resolution\_results and route to a resolver that supports the declared dialect, semantic, owner, and encoding depth                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `MEDIA_BUY_NOT_FOUND`                    | correctable | verify media\_buy\_id; for legacy correlation use get\_media\_buys plus context, such as context.internal\_campaign\_id                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `MULTI_FINALIZE_UNSUPPORTED`             | correctable | sequence single-proposal finalize calls — one finalize entry per get\_products refine\[] call or per refine\_proposals refinements\[] call                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `NOT_CANCELLABLE`                        | correctable | check the seller's cancellation policy or contact the seller                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `PACKAGE_NOT_FOUND`                      | correctable | verify package\_id; for legacy package correlation use get\_media\_buys plus package context, such as context.buyer\_ref                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `PAYMENT_TERMS_NOT_SUPPORTED`            | correctable | omit payment\_terms to accept the seller's default, retry with a different supported value, or negotiate offline                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `PERMISSION_DENIED`                      | correctable | call check\_governance to mint a valid token, or contact the seller to resolve the underlying permission; when error.details.scope is 'agent' with reason 'sandbox\_only' the rejection is terminal-pending-onboarding — surface to a human rather than auto-retrying. For suspended/blocked agent relationships, sellers emit AGENT\_SUSPENDED / AGENT\_BLOCKED instead (those codes carry recovery: terminal directly).                                                                                                                                                    |
| `PIXEL_TRACKER_LOSSY_DOWNGRADE`          | correctable | advisory — emitted alongside the v1 downgrade emission: SDK collapsed a pixel\_tracker asset to v1 <code>{"{asset_type: url, url_type: tracker_pixel}"}</code> for a seller that doesn't support pixel\_tracker natively. The URL still fires; what's lost is in <code>{"error.details.lost_fields"}</code> (event variant, method:js execution context, or custom event timing). Buyer decision: accept the loss (most counter pixels survive), or fail the buy and route to a 3.1-capable seller. Non-fatal — do not auto-retry                                            |
| `PIXEL_TRACKER_UPGRADE_INFERRED`         | correctable | advisory — emitted when a 3.1 SDK upgrades a v1 url+tracker\_pixel asset to pixel\_tracker by inferring event and method from asset\_id conventions. The inference may not match the buyer's original intent; check <code>{"error.details.inferred_event"}</code> / <code>{"inferred_method"}</code> and re-prompt the seller for explicit values if precise measurement matters. Non-fatal — do not auto-retry                                                                                                                                                              |
| `PLACE_TARGET_UNAVAILABLE`               | correctable | resolve the pinned value against the current catalog, review any replacement, and submit an intentional package targeting update                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `PLAN_NOT_FOUND`                         | correctable | verify plan\_id via sync\_plans, or register the plan first                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `POLICY_VIOLATION`                       | correctable | review policy requirements in the error details                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `PRIVATE_FIELD_IN_PUBLIC_PLACEMENT`      | correctable | seller-side fix needed: remove private operational fields (<code>{"visibility"}</code>, <code>{"source"}</code>, <code>{"origin"}</code>, <code>{"delivery_mappings"}</code>, or similar) from public placement objects. Consumers MUST fail closed for the affected placement and alert operators; do not echo private field values in logs or error details                                                                                                                                                                                                                |
| `PRODUCT_EXPIRED`                        | correctable | re-discover with get\_products to find current inventory                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `PRODUCT_NOT_FOUND`                      | correctable | remove invalid IDs and retry, or re-discover with get\_products                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `PRODUCT_UNAVAILABLE`                    | correctable | choose a different product                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `PROPOSAL_EXPIRED`                       | correctable | call request\_proposals and finalize a fresh proposal, or re-discover and finalize through legacy get\_products                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `PROPOSAL_NOT_COMMITTED`                 | correctable | finalize the draft through refine\_proposals, or through the legacy get\_products refine action                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `PROPOSAL_NOT_FOUND`                     | correctable | request and finalize a fresh proposal, then retry                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `PROVENANCE_CLAIM_CONTRADICTED`          | correctable | revise the provenance claim to match the verifier's observation or replace the creative; auto-retry without correction will not pass                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `PROVENANCE_DIGITAL_SOURCE_TYPE_MISSING` | correctable | set provenance.digital\_source\_type to a value from the digital-source-type enum and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `PROVENANCE_DISCLOSURE_MISSING`          | correctable | set provenance.disclosure.required and, when true, populate disclosure.jurisdictions                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `PROVENANCE_EMBEDDED_MISSING`            | correctable | attach at least one embedded\_provenance entry from a supported provider and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `PROVENANCE_REQUIRED`                    | correctable | attach a provenance object - at minimum digital\_source\_type - and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `PROVENANCE_SYNTHETIC_DEPICTION_MISSING` | correctable | assess the creative, set provenance.synthetic\_depiction to true or false, and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `PROVENANCE_VERIFIER_NOT_ACCEPTED`       | correctable | replace verify\_agent.agent\_url with one from the seller's published accepted\_verifiers, drop verify\_agent if the embedding is self-verifiable, or re-embed with a verifier the seller accepts                                                                                                                                                                                                                                                                                                                                                                            |
| `RATE_LIMITED`                           | transient   | wait top-level error.retry\_after seconds when present, then retry                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `READ_ONLY_SCOPE`                        | correctable | use a non-mutating alternative, or surface to the operator to request a scope that permits mutation                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `REFERENCE_NOT_FOUND`                    | correctable | verify the referenced identifier exists and is accessible to the caller                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `REQUOTE_REQUIRED`                       | correctable | refine accepted\_proposal\_id into an amendment and apply it through accept\_proposal, or keep control\_media\_buy inside the accepted envelope; 3.1 compatibility callers must adjust or rediscover                                                                                                                                                                                                                                                                                                                                                                         |
| `SCOPE_INSUFFICIENT`                     | correctable | the agent cannot broaden its own scope - surface to the operator rather than auto-retry                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `SERVICE_UNAVAILABLE`                    | transient   | retry with exponential backoff                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `SESSION_NOT_FOUND`                      | correctable | initiate a new session via si\_initiate\_session                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `SESSION_TERMINATED`                     | correctable | initiate a new session via si\_initiate\_session                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `SIGNAL_NOT_FOUND`                       | correctable | verify signal\_id via get\_signals, or confirm the signal is available from this agent                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `SIGNAL_TARGETING_INCOMPATIBLE`          | correctable | assign the creative to a package whose signal targeting matches the creative's signal\_condition, or rebuild the creative for the package's condition; match on shared signal\_ref identity (compare signal\_agent\_segment\_id exactly when both carry it, else categorical signal\_ref + value)                                                                                                                                                                                                                                                                            |
| `SIGNED_RESPONSE_ENVELOPE_EXPIRED`       | transient   | re-invoke the designated task (verify\_brand\_claim or verify\_brand\_claims) to obtain a freshly signed response with a current exp window                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `SIGNED_RESPONSE_REQUEST_HASH_MISMATCH`  | correctable | re-invoke the designated task with the intended request parameters — the signed response's request\_hash does not match the verifier's recomputed hash of the actual request; if the mismatch persists across retries, investigate JCS request-binding canonicalization between caller and responder                                                                                                                                                                                                                                                                         |
| `SIGNED_RESPONSE_TENANT_MISMATCH`        | correctable | verify the request targeted the correct brand domain and agent\_url, then re-invoke; if the mismatch persists, the responding agent's server-side tenant resolution may be misconfigured                                                                                                                                                                                                                                                                                                                                                                                     |
| `SOURCE_ACCESS_FAILED`                   | correctable | error.field source.locator/source.segment\_ref: fix the reference; error.field source: grant the seller's declared consumer identity and retry; no error.field: vendor outage, retry with backoff                                                                                                                                                                                                                                                                                                                                                                            |
| `STALE_RESPONSE`                         | transient   | advisory — emitted alongside a populated payload that was served from cache past the seller's freshness target because an upstream or sub-agent was unreachable. The response is usable; treat as non-fatal. Inspect <code>{"error.details.cache_age_seconds"}</code> to decide whether to immediately retry for fresh data or accept the cached value; the seller's own service is healthy, so retry is safe (it does not amplify the upstream failure)                                                                                                                     |
| `TERMS_REJECTED`                         | correctable | adjust the proposed terms and retry, or omit measurement\_terms to accept the product's defaults                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `UNPRICEABLE_OUTPUT`                     | correctable | target an output format the transformer prices, or have the seller add a pricing option covering it                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `UNSUPPORTED_FEATURE`                    | correctable | check get\_adcp\_capabilities and remove unsupported fields                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `UNSUPPORTED_GRANULARITY`                | correctable | pick a granularity from the product's reporting\_capabilities.windowed\_pull\_granularities (via get\_adcp\_capabilities) and resubmit, or omit time\_granularity to fall back to cumulative date-range pulls                                                                                                                                                                                                                                                                                                                                                                |
| `UNSUPPORTED_PROVISIONING`               | correctable | re-issue with the entry shape the seller supports — <code>{"account: {account_id: ...}"}</code> for settings-update sellers with account-id namespaces, or <code>{"brand+operator+billing"}</code> for provisioning sellers; check seller documentation or capability declaration for which modes are implemented                                                                                                                                                                                                                                                            |
| `VALIDATION_ERROR`                       | correctable | review error details and fix field values                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `VAST_PARSE_FAILED`                      | correctable | inspect error.details.reason (not\_xml, no\_vast\_root, no\_ad, no\_media\_file), fix the VAST document, and resubmit                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `VAST_VERSION_MISMATCH`                  | correctable | inspect error.details.mismatch\_reason and the corresponding acceptance-set or observed-document fields; select a compatible source representation or correct the offending VAST document                                                                                                                                                                                                                                                                                                                                                                                    |
| `VAST_WRAPPER_DEPTH_EXCEEDED`            | correctable | inspect error.details.reason (depth, loop, timeout); flatten the wrapper chain, reduce redirects below the format's max\_wrapper\_depth, or fix the failing hop                                                                                                                                                                                                                                                                                                                                                                                                              |
| `VERSION_UNSUPPORTED`                    | correctable | re-pin to a release in supported\_versions and retry, or call get\_adcp\_capabilities without a version pin to discover supported\_versions                                                                                                                                                                                                                                                                                                                                                                                                                                  |

### Full descriptions

<AccordionGroup>
  <a id="error-code-account-ambiguous" />

  <Accordion title="ACCOUNT_AMBIGUOUS — correctable">
    **Suggested action:** pass explicit account\_id or a more specific natural key

    Natural key resolves to multiple accounts. Recovery: correctable (pass explicit account\_id or a more specific natural key).
  </Accordion>

  <a id="error-code-account-identity-conflict" />

  <Accordion title="ACCOUNT_IDENTITY_CONFLICT — correctable">
    **Suggested action:** choose a different operator or operator\_unit identity, or retain the account's current identity; do not retry the same desired identity unchanged

    The complete operator\_identity requested through sync\_accounts would rekey the account onto a natural key already owned by another account. The seller MUST reject the change atomically, MUST NOT merge the accounts, and MUST preserve both accounts and every account-scoped resource unchanged. Distinct from CONFLICT, which reports a transient stale revision or concurrent write. Recovery: correctable (choose a different operator or operator\_unit identity, or retain the account's current identity; do not retry the same desired identity unchanged).
  </Accordion>

  <a id="error-code-account-moved" />

  <Accordion title="ACCOUNT_MOVED — correctable">
    **Suggested action:** replace the stale reference with error.details.current\_account, refresh through list\_accounts, and retry with a fresh idempotency key

    An authorized caller used a former natural key that was tombstoned after the same account was rekeyed through sync\_accounts. The seller MUST return the current canonical reference in error.details.current\_account, conforming to error-details/account-moved.json, and MUST NOT provision or resolve a second account from the former key. Sellers retain the tombstone while the account or any account-scoped historical resources are retained. To avoid a cross-tenant existence oracle, sellers return ACCOUNT\_MOVED only when the caller is authorized to resolve the current account; otherwise they return ACCOUNT\_NOT\_FOUND. Recovery: correctable (replace the stale account reference with details.current\_account, refresh through list\_accounts, and retry with a fresh idempotency key).
  </Accordion>

  <a id="error-code-account-not-found" />

  <Accordion title="ACCOUNT_NOT_FOUND — terminal">
    **Suggested action:** verify account via list\_accounts or contact seller

    The account reference could not be resolved. Recovery: terminal (verify account via list\_accounts or contact seller).
  </Accordion>

  <a id="error-code-account-payment-required" />

  <Accordion title="ACCOUNT_PAYMENT_REQUIRED — terminal">
    **Suggested action:** buyer must resolve billing

    Account has an outstanding balance requiring payment before new buys. Recovery: terminal (buyer must resolve billing).
  </Accordion>

  <a id="error-code-account-required" />

  <Accordion title="ACCOUNT_REQUIRED — correctable">
    **Suggested action:** pass account, or reference an existing resource whose owning account the service can resolve

    The service must resolve the commercial account before it can determine governance applicability, but the request and referenced resource do not identify one. Recovery: correctable (pass account, or use a resource bound to an account).
  </Accordion>

  <a id="error-code-account-setup-required" />

  <Accordion title="ACCOUNT_SETUP_REQUIRED — correctable">
    **Suggested action:** check details.setup for URL or instructions

    Natural key resolved but the account needs setup before use. Recovery: correctable (check details.setup for URL or instructions).
  </Accordion>

  <a id="error-code-account-suspended" />

  <Accordion title="ACCOUNT_SUSPENDED — terminal">
    **Suggested action:** contact seller to resolve suspension

    Account has been suspended. Recovery: terminal (contact seller to resolve suspension).
  </Accordion>

  <a id="error-code-action-not-allowed" />

  <Accordion title="ACTION_NOT_ALLOWED — correctable">
    **Suggested action:** branch on error.details.reason: for wrong\_status, wait for or transition to a status listed under the action's allowed\_statuses; for mode\_mismatch, this is a flow switch (not a retry against update\_media\_buy) — follow the mode named in available\_actions\[\<action>].mode; for condition\_unresolved, wait until the seller advertises the action after resolving its opaque condition; for not\_supported\_on\_product or not\_supported\_on\_buy, do not retry — the action is unavailable on this buy and buyer must select a different product or renegotiate

    The requested mutation maps to an action that is not currently available on this media buy. Sellers MUST populate <code>{"error.details"}</code> with <code>{"attempted_action"}</code> (the <code>{"media_buy_valid_action"}</code> value the request maps to), <code>{"reason"}</code> (an <code>{"action-not-allowed-reason"}</code> value: <code>{"wrong_status"}</code>, <code>{"not_supported_on_product"}</code>, <code>{"not_supported_on_buy"}</code>, <code>{"mode_mismatch"}</code>, or <code>{"condition_unresolved"}</code>), and <code>{"currently_available_actions"}</code> (echo of the buy's resolved <code>{"available_actions[]"}</code> so the buyer SDK can offer recovery without a separate get\_media\_buys round-trip). Recovery: correctable when <code>{"reason"}</code> is <code>{"wrong_status"}</code> (wait for or transition to an allowed status), <code>{"mode_mismatch"}</code> (re-issue through the appropriate flow), or <code>{"condition_unresolved"}</code> (wait until the seller can resolve the condition and advertises the action). Terminal-for-this-buy when <code>{"reason"}</code> is <code>{"not_supported_on_product"}</code> or <code>{"not_supported_on_buy"}</code> — buyers select a different product or renegotiate buy terms.
  </Accordion>

  <a id="error-code-agent-blocked" />

  <Accordion title="AGENT_BLOCKED — terminal">
    **Suggested action:** surface to a human at the buyer — the relationship is permanently denied and is reinstated only through offline operator action with the seller, not via any seller-callable AdCP task

    The calling buyer agent's commercial relationship with the seller is permanently denied — the agent is blocked. Sibling to <code>{"AGENT_SUSPENDED"}</code> on the agent-relationship axis but with no recovery path (a suspension may lift via re-onboarding; a block does not). The code itself is the discriminator — same posture as <code>{"AGENT_SUSPENDED"}</code>: no <code>{"error.details"}</code> payload, no per-agent commercial state, cross-tenant onboarding oracle clamp + channel-coverage requirements normative in error-handling.mdx Per-Agent Authorization Gate. Recovery: terminal (no autonomous recovery — the agent MUST surface to a human at the buyer; relationships are reinstated only through offline operator action with the seller, not via any seller-callable AdCP task).
  </Accordion>

  <a id="error-code-agent-suspended" />

  <Accordion title="AGENT_SUSPENDED — terminal">
    **Suggested action:** surface to a human at the buyer — the agent cannot unilaterally lift a suspension; re-onboarding with the seller offline may resolve

    The calling buyer agent's commercial relationship with the seller is temporarily paused — the agent is onboarded but currently suspended. Sibling to <code>{"ACCOUNT_SUSPENDED"}</code> (account-wide) and <code>{"CAMPAIGN_SUSPENDED"}</code> (per-plan) but scoped to the agent-relationship axis (orthogonal to any specific account on that agent). The code itself is the discriminator — it does NOT carry an <code>{"error.details"}</code> payload (mirroring <code>{"BILLING_NOT_PERMITTED_FOR_AGENT"}</code>'s discriminator-by-code pattern), and MUST NOT carry per-agent commercial state (rate cards, payment terms, credit limit, billing entity, contact channels) since full disclosure of per-agent state in a single probe is a per-agent oracle. Cross-tenant onboarding oracle clamp + channel-coverage requirements (response shape, HTTP/A2A/MCP status, headers, side effects, observability, latency parity, retry-counter side channel) are normative in error-handling.mdx Per-Agent Authorization Gate; this description does not restate them to avoid drift. Recovery: terminal (re-onboarding may resolve the suspension; the agent MUST surface to a human at the buyer rather than auto-retrying — the agent cannot unilaterally lift a suspension, and re-attempts only reinforce the gate).
  </Accordion>

  <a id="error-code-ambiguous-bidding-policy" />

  <Accordion title="AMBIGUOUS_BIDDING_POLICY — correctable">
    **Suggested action:** remove either the canonical bidding block or all legacy bidding fields from the effective package

    The same effective package combines the canonical bidding block with legacy bid\_price or monetary optimization-goal target fields, so two bidding interpretations are present. Sellers MUST reject rather than choosing a winner. Recovery: correctable (emit only the 3.2 bidding block or only one legacy representation).
  </Accordion>

  <a id="error-code-audience-too-small" />

  <Accordion title="AUDIENCE_TOO_SMALL — correctable">
    **Suggested action:** broaden targeting or upload more audience members

    Audience segment is below the minimum required size for targeting. Recovery: correctable (broaden targeting or upload more audience members).
  </Accordion>

  <a id="error-code-authorization-required" />

  <Accordion title="AUTHORIZATION_REQUIRED — correctable">
    **Suggested action:** complete or restore the required downstream platform connection, identity, creator, or post authorization; use error.details.missing\_connections, authorization\_url, authorization\_instructions, or reference\_authorization when present

    The caller is authenticated, but the referenced object requires an additional downstream platform connection, identity, creator, or post authorization before the seller can complete the requested action. Typical use: <code>{"sync_creatives"}</code> with a <code>{"published_post"}</code> reference where the seller can resolve the post but the owning identity has not authorized paid serving, or authorization has expired/revoked and can be restored. Distinct from <code>{"AUTH_MISSING"}</code> / <code>{"AUTH_INVALID"}</code> (caller credentials) and from <code>{"PERMISSION_DENIED"}</code> (seller policy denies the caller). Sellers SHOULD include recovery details conforming to <code>{"error-details/authorization-required.json"}</code>, especially <code>{"error.details.missing_connections[]"}</code> when the caller needs to complete one of several platform connections. Legacy recovery hints such as <code>{"authorization_url"}</code>, <code>{"authorization_instructions"}</code>, or <code>{"reference_authorization"}</code> remain valid when safe to disclose. Recovery: correctable (complete or restore the required authorization, then retry).
  </Accordion>

  <a id="error-code-auth-invalid" />

  <Accordion title="AUTH_INVALID — terminal">
    **Suggested action:** do NOT auto-retry — credentials were rejected; rotate keys, refresh OAuth tokens once if applicable, otherwise escalate to a human

    Credentials were presented but rejected — revoked, malformed signature, or a key no longer in the seller's keystore. Sellers MUST return this code when an <code>{"Authorization"}</code> header was present but verification failed. Recovery: terminal. Exception: agents with a valid OAuth 2.1 refresh grant MAY treat this as correctable when the rejection reason is token expiry — silently refresh and retry once; if the refresh fails or the seller explicitly signals revocation, escalate to human.
  </Accordion>

  <a id="error-code-auth-missing" />

  <Accordion title="AUTH_MISSING — correctable">
    **Suggested action:** provide credentials via the auth header and retry

    No credentials were presented. Sellers MUST return this code when no <code>{"Authorization"}</code> header was included in the request. Recovery: correctable (provide credentials via the auth header and retry).
  </Accordion>

  <a id="error-code-auth-required" />

  <Accordion title="AUTH_REQUIRED — correctable">
    **Suggested action:** provide credentials when missing; do NOT auto-retry rejected credentials — escalate for rotation

    **Deprecated** — use <code>{"AUTH_MISSING"}</code> (no credentials presented) or <code>{"AUTH_INVALID"}</code> (credentials presented and rejected). Retained as a backward-compatible alias during the 3.x deprecation window. Recovery: correctable.
  </Accordion>

  <a id="error-code-bidding-placement-conflict" />

  <Accordion title="BIDDING_PLACEMENT_CONFLICT — correctable">
    **Suggested action:** align media-buy and package bidding scopes with the provider's supported placement, or choose a compatible budget mode/product combination

    The authored media-buy/package bidding scopes cannot be represented by the provider's native campaign, package, or shared-strategy placement rules. Sellers MUST detect this before any provider mutation and SHOULD identify the conflicting scopes and provider constraint in error.details. Recovery: correctable (remove or align package overrides, move the policy to the supported scope, or choose a compatible budget mode/product combination).
  </Accordion>

  <a id="error-code-billing-not-permitted-for-agent" />

  <Accordion title="BILLING_NOT_PERMITTED_FOR_AGENT — correctable">
    **Suggested action:** retry with error.details.suggested\_billing (typically 'operator') when present; when absent, surface to a human at the buyer — the agent cannot unilaterally extend its commercial relationship and MUST NOT auto-retry

    The seller's <code>{"supported_billing"}</code> capability accepts the requested model, but the calling buyer agent's commercial relationship with the seller does not — e.g., the agent is onboarded as passthrough-only (no payments relationship — only the operator can be invoiced) and <code>{"billing: 'agent'"}</code> or <code>{"billing: 'advertiser'"}</code> is rejected even though the seller supports both at the capability level. Distinct from <code>{"BILLING_NOT_SUPPORTED"}</code> (seller-wide capability) by being narrowly per-buyer-agent: the gate is the seller's onboarding record for this caller, not the seller's global wire capability. Sellers MUST emit this code only after agent identity has been established via signed-request derivation or a credential-to-agent mapping in the seller's onboarding record; callers without established identity MUST receive <code>{"BILLING_NOT_SUPPORTED"}</code> instead, to prevent the distinct code from acting as an onboarding oracle. The recovery shape is deliberately minimal — <code>{"error.details"}</code> MUST conform to <code>{"error-details/billing-not-permitted-for-agent.json"}</code> (<code>{"rejected_billing"}</code> plus an optional single <code>{"suggested_billing"}</code> retry value, typically <code>{"operator"}</code>) and MUST NOT carry the agent's full permitted-billing subset, rate cards, payment terms, credit limit, billing entity, or any other per-agent commercial state. Recovery: correctable (retry with <code>{"error.details.suggested_billing"}</code> when present; when absent, surface to a human at the buyer — the agent cannot unilaterally extend its commercial relationship and MUST NOT auto-retry, since payments-relationship onboarding with the seller is offline).
  </Accordion>

  <a id="error-code-billing-not-supported" />

  <Accordion title="BILLING_NOT_SUPPORTED — correctable">
    **Suggested action:** check get\_adcp\_capabilities for supported\_billing and resubmit with a supported value, or omit billing to accept the seller's default

    The seller declines the requested <code>{"billing"}</code> value either at the seller-wide capability level (<code>{"supported_billing"}</code> does not include the value) or at the per-account-relationship level (e.g., the seller accepts <code>{"operator"}</code> billing in general but has no direct billing relationship with the operator on this specific account). The default reject code for billing-value mismatches; <code>{"error.details"}</code> SHOULD conform to <code>{"error-details/billing-not-supported.json"}</code> (<code>{"scope"}</code> ∈ <code>{"{\"capability\", \"account\"}"}</code> plus optional <code>{"supported_billing"}</code> echo for the <code>{"\"capability\""}</code> scope) so callers can dispatch without parsing prose. Distinct from <code>{"BILLING_NOT_PERMITTED_FOR_AGENT"}</code>, which is narrowly scoped to the calling buyer agent's commercial relationship with the seller (passthrough-only vs agent-billable) rather than to the seller's capability or per-account state. Sellers MUST emit <code>{"BILLING_NOT_PERMITTED_FOR_AGENT"}</code> only when agent identity has been established via signed-request derivation or a credential-to-agent mapping in the seller's onboarding record; in all other cases (unauthenticated callers and bearer credentials not mapped to a specific agent record) sellers MUST return <code>{"BILLING_NOT_SUPPORTED"}</code> and MUST omit <code>{"error.details.scope"}</code> — emitting the per-agent code or the <code>{"\"account\""}</code>-scope hint without established identity is a cross-tenant onboarding oracle (same uniform-response shape required by the <code>{"*_NOT_FOUND"}</code> family). Recovery: correctable (check <code>{"get_adcp_capabilities"}</code> for <code>{"supported_billing"}</code> and resubmit with a value the seller supports, or omit <code>{"billing"}</code> to accept the seller's default).
  </Accordion>

  <a id="error-code-billing-out-of-band" />

  <Accordion title="BILLING_OUT_OF_BAND — terminal">
    **Suggested action:** do not retry — billing for this account runs through a non-AdCP channel. Pre-filter via capabilities.creative.bills\_through\_adcp before sending report\_usage; flag the account in the buyer's routing table and fall back to the ad server's native billing export for cost reconciliation

    A creative-agent billing-loop operation (<code>{"report_usage"}</code> is the canonical case) received a well-formed record that the agent will not bill on because this account bills via a non-AdCP channel — flat license, SaaS contract, bundled enterprise agreement, or any other out-of-band arrangement. The agent returns <code>{"accepted: 0"}</code> with the offending record(s) listed in <code>{"errors[]"}</code> carrying this code; the request itself is valid and silent acceptance would break buyer-side reconciliation. Distinct from <code>{"BILLING_NOT_SUPPORTED"}</code> (the seller declines a specific <code>{"billing"}</code> value on a media-buy account where AdCP billing is otherwise in scope) and <code>{"BILLING_NOT_PERMITTED_FOR_AGENT"}</code> (per-buyer-agent commercial gate on an otherwise-billable surface) by signaling that the entire billing surface is offline for this account, not that a specific value or caller is rejected. Buyers SHOULD pre-filter by reading <code>{"capabilities.creative.bills_through_adcp"}</code> from <code>{"get_adcp_capabilities"}</code> before issuing <code>{"report_usage"}</code>; agents that have not yet declared the capability remain in the probe-to-discover mode. The error is returned per-record (in the <code>{"report_usage"}</code> response <code>{"errors[]"}</code> array with <code>{"field"}</code> pointing at <code>{"usage[N]"}</code> or a specific record subpath), not at the envelope level. The code itself is the discriminator; no <code>{"error.details"}</code> shape is defined for this code (mirroring <code>{"CONFIGURATION_ERROR"}</code>'s discriminator-by-code pattern). Recovery: terminal — auto-retry will not change the outcome; the buyer SHOULD flag the account in its routing table so reconciliation falls back to the ad server's native billing export (or whatever offline channel the agent uses) rather than expecting AdCP-side cost truth.
  </Accordion>

  <a id="error-code-brand-required" />

  <Accordion title="BRAND_REQUIRED — correctable">
    **Suggested action:** include brand (domain plus optional brand\_id) on the request

    A billable operation was attempted without a brand reference. Every billable operation requires either a seller-assigned <code>{"account_id"}</code> or a natural key including <code>{"brand"}</code>. Recovery: correctable (include <code>{"brand"}</code> — <code>{"domain"}</code> plus optional <code>{"brand_id"}</code> — on the request).
  </Accordion>

  <a id="error-code-budget-cap-reached" />

  <Accordion title="BUDGET_CAP_REACHED — correctable">
    **Suggested action:** raise max\_spend, or reduce max\_creatives/max\_variants, to produce the remaining items

    build\_creative stopped producing early because the next leaf would exceed the request's max\_spend ceiling. Normally a SUCCESSFUL partial build (BuildCreativeVariantSuccess with budget\_status: 'capped' and an advisory BUDGET\_CAP\_REACHED entry — every returned leaf is real and billed); returned as a terminal error only when even the first leaf would exceed the cap (no partial possible). Distinct from BUDGET\_EXCEEDED (would exceed a media-buy/package allocation — a rejection) and BUDGET\_EXHAUSTED (already spent). Recovery: correctable (raise max\_spend, or reduce max\_creatives/max\_variants).
  </Accordion>

  <a id="error-code-budget-exceeded" />

  <Accordion title="BUDGET_EXCEEDED — correctable">
    **Suggested action:** reduce requested amount or increase budget allocation

    Operation would exceed the allocated budget for the media buy or package. Distinct from BUDGET\_EXHAUSTED (already spent) and BUDGET\_TOO\_LOW (below minimum). Recovery: correctable (reduce requested amount or increase budget allocation).
  </Accordion>

  <a id="error-code-budget-exhausted" />

  <Accordion title="BUDGET_EXHAUSTED — terminal">
    **Suggested action:** buyer must add funds or increase budget cap

    Account or campaign budget has been fully spent. Distinct from BUDGET\_TOO\_LOW (rejected at submission). Recovery: terminal (buyer must add funds or increase budget cap).
  </Accordion>

  <a id="error-code-budget-too-low" />

  <Accordion title="BUDGET_TOO_LOW — correctable">
    **Suggested action:** increase budget or check capabilities.media\_buy.limits

    Budget is below the seller's minimum. Recovery: correctable (increase budget or check capabilities.media\_buy.limits).
  </Accordion>

  <a id="error-code-campaign-suspended" />

  <Accordion title="CAMPAIGN_SUSPENDED — transient">
    **Suggested action:** wait for the escalation to resolve; contact the plan operator if the suspension persists

    Campaign governance has been suspended pending human review; the governance agent MUST reject <code>{"check_governance"}</code> and <code>{"report_plan_outcome"}</code> calls on the affected plan until the escalation is resolved. Distinct from <code>{"ACCOUNT_SUSPENDED"}</code> (account-wide) — this is scoped to a single plan/campaign. Recovery: transient (wait for the escalation to resolve; contact the plan operator if the suspension persists).
  </Accordion>

  <a id="error-code-catalog-limit-exceeded" />

  <Accordion title="CATALOG_LIMIT_EXCEEDED — correctable">
    **Suggested action:** remove unused catalogs, or contact the seller to raise the limit

    The account has reached its maximum catalog count. Recovery: correctable (remove unused catalogs, or contact the seller to raise the limit).
  </Accordion>

  <a id="error-code-compliance-unsatisfied" />

  <Accordion title="COMPLIANCE_UNSATISFIED — correctable">
    **Suggested action:** choose a format that supports the required disclosure positions and persistence modes, or remove the disclosure requirement

    A required disclosure from the brief's compliance section cannot be satisfied by the target format — either the required position or the required persistence mode is not in the format's disclosure\_capabilities. Recovery: correctable (choose a format that supports the required disclosure positions and persistence modes, or remove the disclosure requirement).
  </Accordion>

  <a id="error-code-configuration-error" />

  <Accordion title="CONFIGURATION_ERROR — terminal">
    **Suggested action:** surface to a human at the seller — the buyer cannot resolve a seller-side deployment misconfiguration and MUST NOT auto-retry

    The seller's deployment is misconfigured in a way that prevents handling the request — the buyer cannot fix it, retrying will not help, and reporting to the seller's operator is the only remediation. Examples: account declared with <code>{"mode: 'mock'"}</code> but no <code>{"mock_upstream_url"}</code> populated; platform declared with <code>{"mode: 'live'"}</code> or <code>{"mode: 'sandbox'"}</code> but no <code>{"upstream_url"}</code> declared; required environment variable unset on the seller process. Distinct from <code>{"INVALID_REQUEST"}</code> (buyer-fixable; the request itself is malformed), <code>{"SERVICE_UNAVAILABLE"}</code> (transient; retry-with-backoff may succeed), <code>{"UNSUPPORTED_FEATURE"}</code> (capability mismatch — the seller does not implement the requested specialism), <code>{"ACCOUNT_SETUP_REQUIRED"}</code> (buyer-side onboarding incomplete; this code is seller-side deployment incomplete), and <code>{"GOVERNANCE_UNAVAILABLE"}</code> (governance-agent-scoped; transient). Wire placement. The deployment cannot produce a success artifact, so sellers MUST flip transport-level failure markers (HTTP 5xx, MCP <code>{"isError: true"}</code>, A2A <code>{"failed"}</code>) and populate both layers per the two-layer model in <code>{"error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model"}</code>. The code itself is the discriminator; no <code>{"error.details"}</code> shape is defined for this code (mirroring the minimal-disclosure precedent of <code>{"AGENT_SUSPENDED"}</code> / <code>{"AGENT_BLOCKED"}</code>). Sellers SHOULD populate <code>{"error.message"}</code> with operator-actionable detail (which metadata key is missing, which env var is unset) and MUST NOT include credentials, connection strings, or stack traces — the message is wire-visible to the buyer. Recovery: terminal — the buyer MUST surface to the seller's operator and MUST NOT auto-retry (retries cannot resolve a misconfigured deployment until the operator intervenes).
  </Accordion>

  <a id="error-code-conflict" />

  <Accordion title="CONFLICT — transient">
    **Suggested action:** re-read the resource and retry with current state

    Concurrent modification detected. The resource was modified by another request between read and write. Recovery: transient (re-read the resource and retry with current state).
  </Accordion>

  <a id="error-code-conflicting-selectors" />

  <Accordion title="CONFLICTING_SELECTORS — correctable">
    **Suggested action:** emit one canonical format selector route, or make every required legacy 3.x compatibility projection select the same product format contract under the canonical v2-narrows-v1 comparison

    A 3.x package request carries multiple resolvable format selector routes that select different canonical product format declaration sets. Sellers MUST first resolve every present route independently (<code>{"format_option_refs"}</code>, direct <code>{"format_kind"}</code> plus <code>{"params"}</code>, and deprecated <code>{"format_ids"}</code>) without applying precedence. An unresolved option reference or an unprojectable legacy ID is rejected with <code>{"UNSUPPORTED_FEATURE"}</code>, not this code. Once all routes resolve, sellers derive the product <code>{"format_options[]"}</code> entries selected by each route using directional product satisfaction and require those sets to match. Legacy parameter compatibility uses the asymmetric v2-narrows-v1 relation defined by canonical formats, not raw object equality. For fixed-size image selectors, both width and height participate in compatibility. Sellers MUST reject different format shapes, selected option sets, or incompatible dimensions rather than silently choosing the canonical route. <code>{"error.field"}</code> SHOULD point at the conflicting package, and <code>{"error.details"}</code> SHOULD identify the supplied selector routes and their normalized canonical summaries. Recovery: correctable (emit one canonical selector route, or make a required legacy 3.x compatibility projection select the same product format contract).
  </Accordion>

  <a id="error-code-creative-deadline-exceeded" />

  <Accordion title="CREATIVE_DEADLINE_EXCEEDED — correctable">
    **Suggested action:** check creative\_deadline via get\_media\_buys before submitting changes, or negotiate a deadline extension with the seller

    Creative change submitted after the package's creative\_deadline. Distinct from CREATIVE\_REJECTED (content-policy, brand-safety, or accessibility-review failure). Recovery: correctable (check creative\_deadline via get\_media\_buys before submitting changes, or negotiate a deadline extension with the seller).
  </Accordion>

  <a id="error-code-creative-inaccessible" />

  <Accordion title="CREATIVE_INACCESSIBLE — correctable">
    **Suggested action:** verify the asset URLs in creative\_manifest are reachable without agent-side credentials, then re-submit

    A creative governance agent (get\_creative\_features) could not retrieve the submitted creative\_manifest assets for evaluation — an asset URL was unreachable, returned an error, or required credentials the agent does not hold. Distinct from CREATIVE\_NOT\_FOUND (a creative\_id absent from the agent's library, not an asset-fetch failure) and CREATIVE\_REJECTED (assets retrieved but failed creative review). Recovery: correctable (verify the asset URLs are reachable without agent-side credentials, then re-submit).
  </Accordion>

  <a id="error-code-creative-locale-not-accepted" />

  <Accordion title="CREATIVE_LOCALE_NOT_ACCEPTED — correctable">
    **Suggested action:** supply or assign a creative variant matching every in-scope format option's accepted\_language\_ranges, narrow placement scope, choose a compatible format option, or change an ineligible serve\_default

    A creative bound to a locale-constrained product format has no materialized variant matching locale\_policy.accepted\_language\_ranges, lacks protocol-declared locale topology, or uses serve\_default with a seller-ineligible default variant. Seller ranges use RFC 4647 Basic Filtering and are applied independently for every placement where the assignment may serve, before buyer Lookup, locale\_fallbacks, or default selection. Distinct from CREATIVE\_REJECTED because this is a mechanically discoverable assignment-eligibility mismatch, not subjective content review. error.field SHOULD point to the offending creative or assignment; error.details SHOULD include format\_option\_id when present, accepted\_language\_ranges, available\_variant\_locales, and placement identity when applicable. Recovery: correctable (supply or assign a matching materialized locale variant, narrow placement scope, choose a compatible format option, or change an ineligible serve\_default).
  </Accordion>

  <a id="error-code-creative-missing-click-url" />

  <Accordion title="CREATIVE_MISSING_CLICK_URL — correctable">
    **Suggested action:** add the required destination URL and resubmit the creative

    A submitted creative that requires a destination URL does not provide one. Sellers SHOULD identify the missing buyer-visible field in error.field and MUST NOT expose downstream ad-server names or internal object identifiers in the buyer-facing message. Recovery: correctable (add the required destination URL and resubmit the creative).
  </Accordion>

  <a id="error-code-creative-not-found" />

  <Accordion title="CREATIVE_NOT_FOUND — correctable">
    **Suggested action:** verify creative\_id via list\_creatives, or sync\_creatives to register it

    Referenced creative does not exist in the agent's creative library. Recovery: correctable (verify creative\_id via list\_creatives, or sync\_creatives to register it). Sellers MUST return this code uniformly for any creative\_id not owned by the calling account — never distinguish 'exists in another tenant' from 'does not exist', which would enable cross-tenant enumeration.
  </Accordion>

  <a id="error-code-creative-rejected" />

  <Accordion title="CREATIVE_REJECTED — correctable">
    **Suggested action:** revise the creative according to the applicable advertising policy or validated accessibility criteria

    Creative failed content-policy, brand-safety, or accessibility review. For deadline violations, see CREATIVE\_DEADLINE\_EXCEEDED. Accessibility failures SHOULD use structured details conforming to error-details/accessibility-violation.json. Recovery: correctable (revise the creative according to the applicable policy or validated accessibility criteria).
  </Accordion>

  <a id="error-code-creative-representation-unresolved" />

  <Accordion title="CREATIVE_REPRESENTATION_UNRESOLVED — correctable">
    **Suggested action:** inspect every error.details.representation\_rejections entry, then choose a compatible format option or supply a compatible representation

    No representation in a CreativeRepresentationSet is compatible with the selected target capability or product format option. The resolver MUST retain the complete representation set and MUST include one <code>{"error.details.representation_rejections[]"}</code> entry per candidate, conforming to <code>{"error-details/creative-representation-unresolved.json"}</code>; silent seller guessing is forbidden. Recovery: correctable (choose a compatible product/format option, add a compatible representation under a new revision, or fix the rejected asset contract).
  </Accordion>

  <a id="error-code-creative-revision-content-mismatch" />

  <Accordion title="CREATIVE_REVISION_CONTENT_MISMATCH — correctable">
    **Suggested action:** resend the exact content previously bound to this revision\_id, or mint a new revision\_id for changed content

    A sync\_creatives item reused a revision\_id for different canonical revision content under the same creative\_id. Revision identity is scoped to the parent creative and immutable after first acceptance. Sellers MUST evaluate the buyer input before transcoding or normalization, MUST leave the prior creative state unchanged, and SHOULD return details conforming to error-details/creative-revision-content-mismatch.json. Distinct from IDEMPOTENCY\_CONFLICT: idempotency\_key protects one request replay window, while revision identity protects creative content across requests and retention. Recovery: correctable (resend the exact content previously bound to this revision\_id, or mint a new revision\_id for the changed content).
  </Accordion>

  <a id="error-code-creative-size-mismatch" />

  <Accordion title="CREATIVE_SIZE_MISMATCH — correctable">
    **Suggested action:** resize or replace the creative with a size accepted by every selected package that may serve it

    The submitted creative dimensions do not match any size accepted by the selected packages. Sellers SHOULD identify the offending creative in error.field and MAY include the submitted and accepted dimensions in buyer-safe error.details. Recovery: correctable (resize or replace the creative with a size accepted by every selected package that may serve it).
  </Accordion>

  <a id="error-code-creative-validation-failed-generic" />

  <Accordion title="CREATIVE_VALIDATION_FAILED_GENERIC — correctable">
    **Suggested action:** correct the buyer-visible validation problem and resubmit the creative

    The creative failed buyer-correctable validation, but the producer cannot classify the failure with a more specific standard code. Producers SHOULD prefer a specific creative code whenever one applies and MUST keep buyer-facing messages free of vendor identifiers, internal object names, internal IDs, and stack traces. Recovery: correctable (correct the buyer-visible validation problem and resubmit the creative).
  </Accordion>

  <a id="error-code-creative-value-not-allowed" />

  <Accordion title="CREATIVE_VALUE_NOT_ALLOWED — correctable">
    **Suggested action:** pick a value from error.details.allowed\_values (or re-fetch the format) and resubmit

    A submitted text-asset value is not in the format's declared <code>{"allowed_values"}</code> list. Distinct from <code>{"CREATIVE_REJECTED"}</code> (generic creative-review failure) by being a closed-set constraint violation that the buyer can resolve mechanically without policy interpretation — the seller has published the complete list of acceptable values on the format, and any value outside that list is rejected by definition. The seller MUST set <code>{"error.field"}</code> to the offending asset's path within the manifest (e.g., <code>{"creatives[0].creative_manifest.assets[0].value"}</code> or the field name declared by the format) and SHOULD include the format's <code>{"allowed_values"}</code> array in <code>{"error.details.allowed_values"}</code> so the buyer agent can re-prompt its LLM with constrained sampling. Recovery: correctable (select a value from <code>{"allowed_values"}</code> and resubmit).
  </Accordion>

  <a id="error-code-credential-in-args" />

  <Accordion title="CREDENTIAL_IN_ARGS — terminal">
    **Suggested action:** do NOT auto-retry — auto-retry re-logs the credential on each attempt. Move authentication material or caller-supplied trust material out of request args (top-level, <code>{"context"}</code>, <code>{"ext"}</code>, any nested location) onto the relevant transport authentication/trust channel or account provisioning path (Authorization: Bearer, RFC 9421 signature/JWKS, mTLS, MCP/A2A authentication framing); rotate any leaked credential, then resubmit

    The seller detected authentication material or caller-supplied trust material placed in request args (top-level, in <code>{"context"}</code>, in <code>{"ext"}</code>, or any other nested location in the task payload) instead of arriving on the relevant transport authentication or trust channel. This includes buyer-principal credentials that should arrive on the inbound transport (<code>{"Authorization: Bearer"}</code> per RFC 6750 §2 for HTTP, RFC 9421 signature headers for signed requests, MCP/A2A authentication framing per RFC 9728 §3), and evaluator-call credentials or JWK/JWKS/JWKS-URI trust material smuggled into evaluator-related payload fields instead of being established through the creative agent's outbound transport authentication to the evaluator. Distinct from <code>{"AUTH_REQUIRED"}</code> (no credentials presented or presented credentials rejected on the transport channel) and <code>{"PERMISSION_DENIED"}</code> (authenticated caller not authorized for the action). Distinct from the receiver-side credentials carried in <code>{"push_notification_config.authentication.credentials"}</code>, which configure the seller's webhook callback authentication and are not buyer-principal or evaluator-call credentials — those are an explicit carve-out and MUST NOT trigger this code. Sellers SHOULD reject credential-in-args under AdCP 3.1; the requirement upgrades to MUST 90 days after the 3.1 publication date. Recovery: terminal — the agent MUST NOT auto-retry. Auto-retry against this code re-logs the credential on each attempt across the seller's request logs, observability stack, and any LLM-context surfaces in the buyer-side recovery loop, exactly the prompt-injection exfiltration surface that motivated the rule. Wire placement. Sellers MUST flip transport-level failure markers (HTTP 4xx, MCP <code>{"isError: true"}</code>, A2A <code>{"failed"}</code>) and populate both layers per the two-layer model in <code>{"error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model"}</code>. The code itself is the discriminator; no <code>{"error.details"}</code> shape is defined, and <code>{"error.field"}</code> MUST NOT echo the offending credential value or any prefix of it (e.g., <code>{"\"Bearer ey...\""}</code>). <code>{"error.message"}</code> MUST be generic and MUST NOT contain credential material. Sellers MUST drop the smuggled credential from logs, audit rows, and observability spans before persisting the rejection — the rejection itself is otherwise an exfiltration surface.
  </Accordion>

  <a id="error-code-cursor-expired" />

  <Accordion title="CURSOR_EXPIRED — correctable">
    **Suggested action:** obtain a latest checkpoint, rebuild authoritative account snapshots, then drain changes after the checkpoint

    The list\_account\_changes cursor is no longer within the seller's retained account change window. The seller MUST NOT silently restart from the retention boundary. Recovery: correctable (obtain a new starting\_position: latest checkpoint, rebuild every authoritative account snapshot, then drain changes after that checkpoint). error.details SHOULD include available\_since and MAY include a replacement starting-position hint, without disclosing inaccessible history.
  </Accordion>

  <a id="error-code-evaluator-agent-not-accepted" />

  <Accordion title="EVALUATOR_AGENT_NOT_ACCEPTED — correctable">
    **Suggested action:** replace the evaluator agent\_url (evaluator.feature\_agent.agent\_url or the evaluator agent-form agent\_url) with one from the seller's published accepted\_verifiers, or drop the evaluator agent pointer to fall back to seller-default ranking

    Buyer attached an evaluator agent pointer on <code>{"build_creative"}</code> — <code>{"evaluator.feature_agent.agent_url"}</code> or the <code>{"evaluator"}</code> agent-form <code>{"agent_url"}</code> — that does not match (canonicalized per /docs/reference/url-canonicalization: lowercase scheme and host, strip default port, normalize path dot-segments) any entry in the seller's <code>{"creative_policy.accepted_verifiers[].agent_url"}</code>. The producing agent does not call buyer-asserted endpoints outside its allowlist; this mirrors <code>{"PROVENANCE_VERIFIER_NOT_ACCEPTED"}</code> for the gate/rank evaluator path — the buyer represents which on-list agent it used, the seller is the agent-of-record and calls only allowlisted agents. <code>{"error.field"}</code> MUST point at the offending <code>{"agent_url"}</code> path; <code>{"error.details"}</code> SHOULD include a reference to the product whose <code>{"creative_policy.accepted_verifiers"}</code> the buyer should consult. Recovery: correctable (replace the agent\_url with one from the seller's published <code>{"accepted_verifiers"}</code>, or drop the evaluator agent pointer to fall back to seller-default ranking).
  </Accordion>

  <a id="error-code-feed-fetch-failed" />

  <Accordion title="FEED_FETCH_FAILED — correctable">
    **Suggested action:** check URL accessibility, authentication, and that content matches the declared feed\_format

    Platform could not fetch the catalog feed URL during sync\_catalogs. Recovery: correctable (check URL accessibility, authentication, and that the content matches the declared feed\_format).
  </Accordion>

  <a id="error-code-field-not-permitted" />

  <Accordion title="FIELD_NOT_PERMITTED — correctable">
    **Suggested action:** drop the disallowed field(s) and retry

    A request field is not in the caller's <code>{"field_scopes"}</code> allowlist for this task. Sellers declaring <code>{"field_scopes"}</code> on the account's <code>{"authorization"}</code> object MUST reject any request that sets a non-allowlisted field with this code. Distinct from <code>{"VALIDATION_ERROR"}</code> (schema/business-rule violation) - the field is valid, just not writable by this caller. <code>{"error.field"}</code> MUST identify the exact offending field path (e.g., <code>{"packages[0].budget"}</code>); when multiple fields are disallowed, sellers SHOULD return one error per field, or MAY enumerate them in <code>{"error.details.fields"}</code>. Recovery: correctable and agent-autonomous - agent may drop the disallowed field(s) and retry.
  </Accordion>

  <a id="error-code-format-declaration-divergent" />

  <Accordion title="FORMAT_DECLARATION_DIVERGENT — correctable">
    **Suggested action:** advisory — seller-side fix needed: producer is emitting disagreeing format\_ids and format\_options for the same product. Buyer SDK SHOULD prefer format\_options and surface the divergent product to operators; do not auto-retry

    Non-fatal advisory raised when a product carries BOTH <code>{"format_ids"}</code> (v1) AND <code>{"format_options"}</code> (v2) and the two disagree (different canonical, different dimensions, different orientation) after projection. The producer's contract is that both shapes MUST refer to the same underlying declaration; divergence is a producer bug.

    Either side MAY emit this code: a SELLER may self-detect on emit (own producer bug; rare), or more commonly a consumer-SDK detects on consumption. SDKs MUST prefer <code>{"format_options"}</code> (the richer surface) when both are present and MUST surface the divergent product so it's observable rather than silently picked-one-and-dropped-other. Hard-failing the entire <code>{"get_products"}</code> response is discouraged — it punishes downstream buyers for the producer bug.

    **Surface placement (normative).** Same single-surface mandate as <code>{"FORMAT_PROJECTION_FAILED"}</code>: SDKs that detect this on consumption MUST augment the response's <code>{"errors[]"}</code> array with an entry carrying <code>{"source: \"sdk\""}</code>, <code>{"sdk_id: \"<package>@<version>\""}</code>, <code>{"code: \"FORMAT_DECLARATION_DIVERGENT\""}</code>, and the field+details described below. Logger-only is insufficient; lint-output channels are NOT acceptable as the surface (the multi-hop agent network needs warnings to propagate across SDK boundaries via the wire response).

    <code>{"error.field"}</code> MUST point at the offending product; <code>{"error.details"}</code> SHOULD carry <code>{"{ product_id, format_ids, format_options_summary, divergence_reason }"}</code> so buyer SDKs can flag the producer for follow-up.

    **Multi-hop deduplication.** Each hop that detects the same divergence SHOULD deduplicate by <code>{"(code, field)"}</code> rather than re-emit; the existing entry's <code>{"sdk_id"}</code> identifies which earlier processor saw it first.

    Recovery: correctable but seller-side — buyer can't fix divergent declarations, only flag them.
  </Accordion>

  <a id="error-code-format-declaration-v1-ambiguous" />

  <Accordion title="FORMAT_DECLARATION_V1_AMBIGUOUS — correctable">
    **Suggested action:** advisory — seller-side fix needed: the v2 declaration's canonical has only family-level structural registry entries (no invertible literal). Seller MUST author v1\_format\_ref on the v2 declaration to disambiguate; SDKs MUST NOT synthesize. Do not auto-retry

    Non-fatal advisory raised when an SDK detects that a product's v2 declaration cannot be unambiguously projected back to a single v1 named format because the v1-canonical-mapping registry has only family-level structural entries for this canonical (no invertible <code>{"format_id_glob"}</code> literal). The family is known (e.g., 'this is a video\_vast'); the specific v1 named format isn't pickable mechanically. Distinct from <code>{"FORMAT_PROJECTION_FAILED"}</code> (registry-coverage gap, correctable by adding a registry entry) — ambiguity is structural: the family is defined but a specific format can't be picked without seller assertion.

    Surface placement: same single-mandate as <code>{"FORMAT_PROJECTION_FAILED"}</code> and <code>{"FORMAT_DECLARATION_DIVERGENT"}</code> — SDKs MUST augment the response's <code>{"errors[]"}</code> array with an entry carrying <code>{"source: \"sdk\""}</code>, <code>{"sdk_id"}</code>, <code>{"code: \"FORMAT_DECLARATION_V1_AMBIGUOUS\""}</code>, <code>{"field"}</code> pointing at the offending declaration, and <code>{"error.details"}</code> SHOULD carry <code>{"{ format_kind, registry_matches: [<list of structural entries that matched at family level>], product_id }"}</code> so adopters can see why the inversion was ambiguous.

    **SDKs MUST NOT synthesize a v1\_format\_ref** in this case (or any other case). v1↔v2 explicit pairing is seller-asserted only — SDKs encountering family-only registry matches MUST treat the v2 declaration as v1-unreachable and surface this code rather than invent a plausible v1 format\_id. The seller's path: author <code>{"v1_format_ref"}</code> on the v2 declaration to disambiguate (the authoritative pairing per <code>{"v1-canonical-mapping.json"}</code> resolution step 1), or accept that v1-only buyers won't see this product. Recovery: correctable but seller-side — buyer can't disambiguate without the seller's assertion.
  </Accordion>

  <a id="error-code-format-declaration-v1-lossy-multi-size" />

  <Accordion title="FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE — correctable">
    **Suggested action:** advisory — emitted alongside the partial v1 emission, NOT in place of it: the v2 declaration carries <code>{"params.sizes[]"}</code> with N entries but only M v1\_format\_ref entries (M \< N), so v1 buyers see partial size coverage on the product. Seller-side fix: add v1\_format\_ref entries for the missing sizes. SDK MAY (non-normative) fan out automatically by catalog lookup. Non-fatal — do not auto-retry

    Non-fatal advisory raised when a v2 declaration carries <code>{"params.sizes[]"}</code> with N entries but only M v1\_format\_ref entries (M \< N). The seller has asserted some v1 named formats but not enough to cover all declared sizes — v1-only buyers see partial coverage on the product. Emitted **alongside** the partial v1 emission (NOT in place of it): the product still appears on the v1 wire under the M sizes the seller covered; this code tells v1-aware downstream agents that N-M sizes were dropped from the projection.

    Surface placement: SDKs that detect on emission OR consumption MUST augment the response's <code>{"errors[]"}</code> with <code>{"source: \"sdk\""}</code> (or <code>{"\"producer\""}</code> if the seller self-detects on emit), <code>{"sdk_id"}</code>, <code>{"code: \"FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE\""}</code>, <code>{"field"}</code> pointing at the offending declaration, and <code>{"error.details"}</code> SHOULD carry <code>{"{ product_id, declared_sizes: [{w,h}, …], covered_sizes: [{w,h}, …], dropped_sizes: [{w,h}, …] }"}</code> so buyer agents see which sizes were lost.

    **SDKs MAY (non-normative) fan out automatically** by catalog lookup — for each entry in <code>{"sizes[]"}</code> lacking a corresponding <code>{"v1_format_ref"}</code>, the SDK consults the AAO catalog for the per-size v1 named format (e.g., for <code>{"{width: 728, height: 90}"}</code> look up <code>{"display_728x90_image"}</code>) and emits it under <code>{"format_ids[]"}</code>. This is opt-in (requires catalog access); when SDKs fan out, they SHOULD still emit this code as a transparency advisory so downstream consumers know the v1 emit was synthesized rather than seller-asserted.

    Recovery: warning — non-fatal, no retry. Seller fix: add <code>{"v1_format_ref[]"}</code> entries for the missing sizes.
  </Accordion>

  <a id="error-code-format-not-supported" />

  <Accordion title="FORMAT_NOT_SUPPORTED — correctable">
    **Suggested action:** refresh get\_adcp\_capabilities creative.supported\_formats\[] and retry with a capability\_id whose operations contains the intended build, preview, or validate operation

    A requested creative operation route is not supported by this creative agent. On the canonical 3.2 path, returned when build\_creative.target\_capability\_id(s), preview\_creative.target\_capability\_id, or validate\_input targets\[] kind capability does not match an advertised creative.supported\_formats\[].capability\_id carrying the requested operation. Also returned when preview renderer inference has zero or multiple compatible matches. Sellers SHOULD attribute the error to the selector field and MAY include supported capability IDs in error.details.supported\_capability\_ids when safe. Deprecated target\_format\_id(s) and preview format\_id retain legacy named-format error attribution during the 3.x compatibility window. Recovery: correctable (read get\_adcp\_capabilities creative.supported\_formats\[] and retry with a capability\_id whose operations contains the intended operation).
  </Accordion>

  <a id="error-code-format-option-unresolved" />

  <Accordion title="FORMAT_OPTION_UNRESOLVED — correctable">
    **Suggested action:** advisory — publisher-side fix needed: a placement's <code>{"format_options[].format_option_id"}</code> references a <code>{"format_option_id"}</code> that does not exist in this file's top-level <code>{"formats[]"}</code>. Buyer SDK MUST fail closed for that placement (drop the format from the placement's accepted set) and surface this code. Publisher fix: either declare the missing format option in <code>{"formats[]"}</code> or remove the reference from the placement. Do not auto-retry

    Non-fatal advisory raised when a placement in <code>{"adagents.json"}</code> (or any consumer of <code>{"placement-definition.json"}</code>) carries <code>{"format_options[].format_option_id"}</code> referencing a <code>{"format_option_id"}</code> that does NOT exist in the file's top-level <code>{"formats[]"}</code>. The reference is broken — the publisher's catalog claims the placement accepts a format option that isn't declared.

    **Resolution scope is same-file only.** Cross-file <code>{"format_option_id"}</code> lookup is not supported by design (closes off format\_option\_id squatting across publisher boundaries — a malicious file cannot reference another publisher's format\_option\_id and claim its narrowing). Buyer SDKs MUST fail closed for the placement (drop the format from the placement's accepted format set) and MUST surface this code rather than silently dropping or guessing what the publisher meant.

    Surface placement: same single-mandate as the other FORMAT\_\* codes — SDKs that detect on consumption MUST augment the response's <code>{"errors[]"}</code> with <code>{"source: \"sdk\""}</code>, <code>{"sdk_id"}</code>, <code>{"code: \"FORMAT_OPTION_UNRESOLVED\""}</code>, <code>{"field"}</code> pointing at the offending placement (e.g., <code>{"placements[2].format_options[1].format_option_id"}</code>), and <code>{"error.details"}</code> SHOULD carry <code>{"{ placement_id, format_option_id, declared_format_options: [<list of format_option_ids actually in formats[]>] }"}</code> so the publisher can fix.

    Recovery: correctable but publisher-side — buyer can't fix; publisher either declares the missing format option in <code>{"formats[]"}</code> or removes the reference from the placement.
  </Accordion>

  <a id="error-code-format-projection-failed" />

  <Accordion title="FORMAT_PROJECTION_FAILED — correctable">
    **Suggested action:** advisory — seller-side fix needed: ask the seller to add an explicit <code>{"canonical"}</code> field on the legacy format declaration, or contribute a registry entry (format\_id\_glob or structural match) to v1-canonical-mapping.json. Do not auto-retry; the product is still valid on the legacy named-format path

    Non-fatal advisory raised when a legacy named format on a product cannot be projected to a canonical-formats <code>{"ProductFormatDeclaration"}</code> via the resolution order in <code>{"v1-canonical-mapping.json"}</code> (explicit <code>{"canonical"}</code> field → format\_id\_glob → structural match → fail-closed). The product is still valid on the legacy named-format path; only the 3.1+ <code>{"format_options"}</code> projection failed. Primarily a **consumer-SDK concern** — the seller didn't fail; the consumer-side SDK couldn't project on their behalf. <code>{"error.field"}</code> MUST point at the offending product (e.g., <code>{"products[3].format_ids[0]"}</code>); <code>{"error.details"}</code> SHOULD carry <code>{"{ format_id, product_id, resolution_failure: \"no_explicit_canonical\" \u007c \"no_registry_match\" \u007c \"no_structural_match\" }"}</code> so buyer SDKs can route remediation (suggest the seller add an explicit <code>{"canonical"}</code> field, or file a registry PR).

    **Surface placement (normative).** SDKs that detect this on consumption MUST augment the response's <code>{"errors[]"}</code> array with an entry carrying <code>{"source: \"sdk\""}</code>, <code>{"sdk_id: \"<package>@<version>\""}</code>, <code>{"code: \"FORMAT_PROJECTION_FAILED\""}</code>, and the field+details described above. This is the single mandated surface — logger-only is insufficient and a separate lint-output channel is NOT acceptable (AdCP is a multi-hop agent network; warnings need to propagate across hops or each hop has to re-detect locally). Sellers MAY emit this code on their own response when they self-detect a non-projectable format on emit; producer-emitted entries omit <code>{"source"}</code> (or set <code>{"source: \"producer\""}</code>). The response stays 200/success regardless of who emits; this is non-fatal.

    **Multi-hop deduplication.** Each hop that detects the same condition SHOULD deduplicate by <code>{"(code, field)"}</code> rather than re-emit. The existing entry's <code>{"sdk_id"}</code> identifies which earlier processor saw it first; downstream SDKs SHOULD NOT add a second entry for the same <code>{"(code, field)"}</code> pair unless they have materially different <code>{"error.details"}</code> (e.g., a different <code>{"resolution_failure"}</code> reason from a different registry version).

    Recovery: correctable (seller-side action — add explicit <code>{"canonical"}</code> field on the legacy format file, contribute a v1-canonical-mapping registry entry, or author a 3.1+ <code>{"ProductFormatDeclaration"}</code> with <code>{"v1_format_ref"}</code> linking back). See canonical-formats.mdx 'Dual emission and v2↔v1 projection' for the full rules.
  </Accordion>

  <a id="error-code-format-shape-promoted" />

  <Accordion title="FORMAT_SHAPE_PROMOTED — correctable">
    **Suggested action:** advisory — migrate the legacy custom format\_shape to error.details.promoted\_to before error.details.transition\_end; dual emission is allowed during the transition window. Do not auto-retry

    Non-fatal deprecation advisory raised when a 3.2-aware SDK encounters <code>{"format_kind: custom"}</code> with a <code>{"format_shape"}</code> that has been promoted to a first-class canonical. SDKs MUST preserve the declaration during its transition window and SHOULD augment the containing response's <code>{"errors[]"}</code> with <code>{"source: sdk"}</code>, <code>{"sdk_id"}</code>, this code, and <code>{"details: { format_shape, promoted_to, promotion_release, transition_end }"}</code>. Producers that self-detect their own legacy declaration MAY emit the same advisory with <code>{"source: producer"}</code>. Recovery is seller-side: dual-emit during the published transition window, migrate consumers, then replace the custom declaration with the promoted canonical.
  </Accordion>

  <a id="error-code-governance-agent-not-accepted" />

  <Accordion title="GOVERNANCE_AGENT_NOT_ACCEPTED — correctable">
    **Suggested action:** select a governance agent matching <code>{"error.details.accepted_governance_agents"}</code>, then retry <code>{"sync_governance"}</code> with a fresh idempotency key

    The governance agent proposed in <code>{"sync_governance"}</code> does not satisfy the seller's authoritative per-account acceptance criteria. The failed binding MUST NOT be persisted or contacted, and credentials supplied for it MUST NOT be echoed in responses or logs. <code>{"error.details"}</code> SHOULD conform to <code>{"error-details/governance-agent-not-accepted.json"}</code>. Distinct from <code>{"GOVERNANCE_UNAVAILABLE"}</code>, which means a verification criterion or registry could not be resolved and is retryable. Recovery: correctable (select an agent satisfying the returned criteria or resolve the account-specific requirement with the seller).
  </Accordion>

  <a id="error-code-governance-denied" />

  <Accordion title="GOVERNANCE_DENIED — correctable">
    **Suggested action:** restructure the buy, escalate to human spending authority, or contact the governance agent for details

    A registered governance agent denied the transaction. Sellers MUST place the denial in the operation's structured rejection arm when one exists (e.g., <code>{"acquire_rights"}</code> → <code>{"AcquireRightsRejected"}</code>, or an <code>{"approval_webhook"}</code> delivery → <code>{"CreativeRejected"}</code>); otherwise in <code>{"errors[]"}</code> + <code>{"adcp_error"}</code>. Buyers MUST dispatch on the response's discriminated <code>{"status"}</code> first and fall back to <code>{"errors[].code"}</code> / <code>{"adcp_error.code"}</code> only when no rejection arm exists for that operation. The buyer may restructure the buy (e.g., reduce budget, split into smaller transactions), escalate to human spending authority, or contact the governance agent for details. Recovery: correctable.

    Wire placement (full guidance). Governance denial is a structured business outcome, not a system error — the governance call SUCCEEDED and the agent returned a denial verdict. Two cases:

    1. Operation or webhook payload defines a structured rejection arm. The arm IS the canonical denial shape. The seller populates <code>{"reason"}</code> (human-readable, propagating governance findings) and <code>{"suggestions"}</code> (optional) and does NOT additionally emit <code>{"GOVERNANCE_DENIED"}</code> in <code>{"errors[]"}</code> or <code>{"adcp_error"}</code>. The rejection arms enforce this at the schema layer: e.g., <code>{"AcquireRightsRejected"}</code> and <code>{"CreativeRejected"}</code> both declare <code>{"not: { required: [errors] }"}</code>, so dual-emission is already a schema violation. The code does not appear on the wire when the rejection arm is used. Transport-level success markers MUST NOT be flipped (HTTP 200, MCP <code>{"isError: false"}</code>, A2A <code>{"succeeded"}</code>) — the operation completed successfully and produced a structured response.

    2. Operation response has no rejection arm (e.g., <code>{"create_media_buy"}</code> returns Success / Error / Submitted arms only). The seller populates <code>{"errors[].code: GOVERNANCE_DENIED"}</code> in the payload AND <code>{"adcp_error.code: GOVERNANCE_DENIED"}</code> on the envelope per the two-layer model in <code>{"error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model"}</code>. Transport-level failure markers DO flip in this case (HTTP 4xx, MCP <code>{"isError: true"}</code>, A2A <code>{"failed"}</code>) — the task could not produce a success artifact.

    The rule generalizes to any current or future operation or webhook payload whose response defines a discriminated rejection arm. In either placement, sellers SHOULD propagate governance findings verbatim — buyers' recovery decisions depend on what specifically was rejected. <code>{"GOVERNANCE_DENIED"}</code> is reserved for verdicts received from a reachable governance agent; if the governance call itself failed (timeout, network, config error), use <code>{"GOVERNANCE_UNAVAILABLE"}</code> instead.
  </Accordion>

  <a id="error-code-governance-unavailable" />

  <Accordion title="GOVERNANCE_UNAVAILABLE — transient">
    **Suggested action:** retry with backoff; if the agent remains unreachable, the buyer MUST contact the plan's governance operator

    A registered governance agent is unreachable. Sellers MUST place this code in <code>{"errors[]"}</code> + <code>{"adcp_error"}</code> (never a structured rejection arm) and flip transport-level failure markers (HTTP 5xx, MCP <code>{"isError: true"}</code>, A2A <code>{"failed"}</code>). Distinct from <code>{"GOVERNANCE_DENIED"}</code> (agent reachable and explicitly denied — see that code's wire-placement guidance). Recovery: transient (retry with backoff; if the agent remains unreachable, the buyer MUST contact the plan's governance operator — the seller MUST NOT proceed with the media buy without a valid decision).

    Wire placement (full guidance). Governance unavailability is a system error — the governance call FAILED (timeout, network, config error) and the seller could not get a verdict at all. Always populate both layers per the two-layer model in <code>{"error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model"}</code>. Do NOT use a structured rejection arm for unavailability even when the task offers one — the buyer's recovery semantics differ (retry-with-backoff for unavailability vs. restructure-or-escalate for denial), and conflating them masks the system-error signal.
  </Accordion>

  <a id="error-code-idempotency-conflict" />

  <Accordion title="IDEMPOTENCY_CONFLICT — correctable">
    **Suggested action:** use a fresh UUID v4 for the new request, or resend the exact original payload to get the cached response

    An earlier request with the same idempotency\_key was processed with a different canonical payload within the seller's replay window. Distinct from CONFLICT (concurrent write) — this indicates the client reused a key across semantically different requests. Recovery: correctable (use a fresh UUID v4 for the new request, or resend the exact original payload to get the cached response).
  </Accordion>

  <a id="error-code-idempotency-expired" />

  <Accordion title="IDEMPOTENCY_EXPIRED — correctable">
    **Suggested action:** perform a natural-key check to determine whether the original request succeeded; if no evidence of success, generate a fresh idempotency\_key for a new attempt

    The idempotency\_key was seen previously but its cached response has been evicted because it is past the seller's declared replay\_ttl\_seconds. Distinct from IDEMPOTENCY\_CONFLICT (different payload within window) — this indicates the retry arrived too late for at-most-once guarantees. Recovery: correctable (perform a natural-key reconciliation — e.g., call get\_media\_buys for the relevant account/status scope and match returned media\_buys\[].context.internal\_campaign\_id — to determine whether the original request succeeded, then either accept that result or generate a fresh idempotency\_key for a new attempt). If the buyer has any evidence the prior call succeeded (partial response received before crash, entry in the buyer's own DB, a webhook fired), the buyer MUST do the natural-key reconciliation BEFORE minting a new key — minting a new key in that situation is exactly how double-creation happens.
  </Accordion>

  <a id="error-code-idempotency-in-flight" />

  <Accordion title="IDEMPOTENCY_IN_FLIGHT — transient">
    **Suggested action:** wait top-level error.retry\_after seconds and retry with the SAME idempotency\_key — MUST NOT mint a fresh key (turns a safe retry into a double-execution race)

    A prior request with the same <code>{"idempotency_key"}</code> is still being processed and has not yet produced a cached response. The second request arrived before the first completed. Sellers MAY return this code instead of blocking the second caller until the first finishes — useful when the first call invokes a slow downstream system (SSP, ad server, payment provider). Distinct from IDEMPOTENCY\_CONFLICT (different canonical payload — a client bug) and from CONFLICT (concurrent modification of a different resource) — IDEMPOTENCY\_IN\_FLIGHT is the seller telling the buyer 'your retry was correct but your previous attempt is still running, come back shortly.' Sellers SHOULD populate top-level <code>{"error.retry_after"}</code> with an integer-second wait hint based on the first request's elapsed time and expected completion. Buyers MUST treat this as transient and MUST NOT mint a fresh <code>{"idempotency_key"}</code> — minting a new key turns a safe retry into a double-execution race. Recovery: transient (wait <code>{"error.retry_after"}</code> seconds and retry with the same <code>{"idempotency_key"}</code>; the second attempt will either replay the now-cached response or, if still in flight, return IDEMPOTENCY\_IN\_FLIGHT again).
  </Accordion>

  <a id="error-code-invalid-feed-format" />

  <Accordion title="INVALID_FEED_FORMAT — correctable">
    **Suggested action:** verify the feed content matches the declared format

    Catalog feed content does not match the declared feed\_format. Recovery: correctable (verify the feed content matches the declared format, e.g. XML for google\_merchant\_center).
  </Accordion>

  <a id="error-code-invalid-pricing-option" />

  <Accordion title="INVALID_PRICING_OPTION — correctable">
    **Suggested action:** verify pricing\_option\_id against the product's pricing\_options from get\_products or the vendor's discovery response, then resubmit with a valid ID

    A <code>{"pricing_option_id"}</code> referenced in the request does not exist on the target account or product. Returned per-record in <code>{"report_usage"}</code> responses and at the request level for <code>{"create_media_buy"}</code> when the submitted pricing option cannot be resolved. <code>{"error.field"}</code> SHOULD point at the offending record path (e.g., <code>{"usage[1].pricing_option_id"}</code> or <code>{"packages[0].pricing_option_id"}</code>). Distinct from <code>{"PRODUCT_NOT_FOUND"}</code> (the product itself is unknown) by being narrowly about a pricing option within a known product or account. Recovery: correctable (verify <code>{"pricing_option_id"}</code> against the product's <code>{"pricing_options"}</code> from <code>{"get_products"}</code> or the vendor's discovery response, then resubmit with a valid ID).
  </Accordion>

  <a id="error-code-invalid-request" />

  <Accordion title="INVALID_REQUEST — correctable">
    **Suggested action:** check request parameters and fix

    Request is malformed, missing required fields, or violates schema constraints. Recovery: correctable (check request parameters and fix).
  </Accordion>

  <a id="error-code-invalid-state" />

  <Accordion title="INVALID_STATE — correctable">
    **Suggested action:** check current status via get\_media\_buys and adjust request

    Operation is not permitted for the resource's current status (e.g., updating a completed or canceled media buy, or modifying a canceled package). Recovery: correctable (check current status via get\_media\_buys and adjust request).
  </Accordion>

  <a id="error-code-invalid-usage-data" />

  <Accordion title="INVALID_USAGE_DATA — correctable">
    **Suggested action:** check required fields for the vendor type (vendor\_cost, currency, account at minimum), fix invalid values, and resubmit

    A usage record in <code>{"report_usage"}</code> has missing or invalid fields — required fields absent, values out of range, or type mismatches. Returned per-record in the <code>{"report_usage"}</code> response <code>{"errors[]"}</code> array. <code>{"error.field"}</code> SHOULD point at the offending field path (e.g., <code>{"usage[0].vendor_cost"}</code>, <code>{"usage[0].currency"}</code>). Distinct from <code>{"INVALID_REQUEST"}</code> (top-level request malformed) by being scoped to individual usage records within an otherwise well-formed request. Recovery: correctable (check required fields for the vendor type — at minimum <code>{"vendor_cost"}</code>, <code>{"currency"}</code>, and <code>{"account"}</code> — fix the offending values, and resubmit).
  </Accordion>

  <a id="error-code-io-required" />

  <Accordion title="IO_REQUIRED — correctable">
    **Suggested action:** review the proposal's insertion\_order, accept terms, and include io\_acceptance on accept\_proposal; use create\_media\_buy only for 3.x compatibility

    The committed proposal requires a signed insertion order but no io\_acceptance was provided. Recovery: correctable (review the proposal's insertion\_order, accept terms, and include io\_acceptance on accept\_proposal; 3.x compatibility callers use create\_media\_buy).
  </Accordion>

  <a id="error-code-item-validation-failed" />

  <Accordion title="ITEM_VALIDATION_FAILED — correctable">
    **Suggested action:** check item\_issues for per-item rejection reasons and fix the offending items

    One or more catalog items failed schema validation during sync\_catalogs. Recovery: correctable (check item\_issues for per-item rejection reasons and fix the offending items).
  </Accordion>

  <a id="error-code-macro-resolution-failed" />

  <Accordion title="MACRO_RESOLUTION_FAILED — correctable">
    **Suggested action:** inspect error.details.macro\_resolution\_results and route to a resolver that supports the declared dialect, semantic, owner, and encoding depth

    One or more declared creative macro tokens cannot be resolved or safely preserved under the selected product and seller capability intersection. Sellers MUST include per-token <code>{"error.details.macro_resolution_results"}</code>, conforming to <code>{"error-details/macro-resolution-failed.json"}</code>; unknown or ambiguous tokens remain byte-preserved and MUST NOT receive guessed values. Recovery: correctable (route to a compatible execution path, correct the verified declaration, or assign the proper downstream resolver).
  </Accordion>

  <a id="error-code-media-buy-not-found" />

  <Accordion title="MEDIA_BUY_NOT_FOUND — correctable">
    **Suggested action:** verify media\_buy\_id; for legacy correlation use get\_media\_buys plus context, such as context.internal\_campaign\_id

    Referenced media buy does not exist or is not accessible to the requesting agent. Recovery: correctable (verify media\_buy\_id; when recovering across legacy sellers or missing echoed IDs, reconcile via get\_media\_buys and the opaque request/response context correlation handle, such as context.internal\_campaign\_id, rather than deprecated top-level buyer\_ref).
  </Accordion>

  <a id="error-code-multi-finalize-unsupported" />

  <Accordion title="MULTI_FINALIZE_UNSUPPORTED — correctable">
    **Suggested action:** sequence single-proposal finalize calls — one finalize entry per get\_products refine\[] call or per refine\_proposals refinements\[] call

    Returned by sellers that cannot guarantee atomic commit across multiple proposals in a single finalize batch. Two call sites where this applies: (1) a <code>{"get_products"}</code> call with multiple <code>{"action: 'finalize'"}</code> entries in <code>{"refine[]"}</code> targeting different <code>{"proposal_id"}</code> values; (2) a <code>{"refine_proposals"}</code> call with multiple <code>{"action: 'finalize'"}</code> entries in <code>{"refinements[]"}</code> targeting different <code>{"proposal_id"}</code> values. The buyer's intent — atomic multi-proposal finalize — is structurally well-formed and per spec atomic on both surfaces, but this seller's downstream stack cannot satisfy the atomicity guarantee (e.g., the proposals route to two different ad servers with no 2PC). More specific than <code>{"INVALID_REQUEST"}</code> so buyers can distinguish 'this seller doesn't support multi-finalize' from 'the request itself is malformed'. Recovery: correctable (sequence the finalize calls one-<code>{"proposal_id"}</code>-per-call on whichever task surface the buyer is using; there is no capability flag for multi-finalize support, so a successful first-attempt is the only positive discovery signal). See [refinement guide § Finalize is exclusive](/docs/media-buy/product-discovery/refinement#finalize-is-exclusive-within-refine).
  </Accordion>

  <a id="error-code-not-cancellable" />

  <Accordion title="NOT_CANCELLABLE — correctable">
    **Suggested action:** check the seller's cancellation policy or contact the seller

    The media buy or package cannot be canceled in its current state. The seller may have contractual or operational constraints that prevent cancellation. Recovery: correctable (check the seller's cancellation policy or contact the seller).
  </Accordion>

  <a id="error-code-package-not-found" />

  <Accordion title="PACKAGE_NOT_FOUND — correctable">
    **Suggested action:** verify package\_id; for legacy package correlation use get\_media\_buys plus package context, such as context.buyer\_ref

    Referenced package does not exist within the specified media buy. Recovery: correctable (verify package\_id within the media buy; when recovering across legacy sellers or missing echoed product\_id, reconcile via get\_media\_buys and the package-level context correlation handle, such as context.buyer\_ref, rather than deprecated top-level buyer\_ref).
  </Accordion>

  <a id="error-code-payment-terms-not-supported" />

  <Accordion title="PAYMENT_TERMS_NOT_SUPPORTED — correctable">
    **Suggested action:** omit payment\_terms to accept the seller's default, retry with a different supported value, or negotiate offline

    The seller does not accept the requested <code>{"payment_terms"}</code> value for this account. Payment terms are never silently remapped — sellers either accept or reject. Distinct from <code>{"BILLING_NOT_SUPPORTED"}</code> (the <code>{"billing"}</code> enum) by being narrowly about the <code>{"payment_terms"}</code> enum on the same account. Recovery: correctable (omit <code>{"payment_terms"}</code> to accept the seller's default, retry with a different value the seller supports, or negotiate offline).
  </Accordion>

  <a id="error-code-permission-denied" />

  <Accordion title="PERMISSION_DENIED — correctable">
    **Suggested action:** call check\_governance to mint a valid token, or contact the seller to resolve the underlying permission; when error.details.scope is 'agent' with reason 'sandbox\_only' the rejection is terminal-pending-onboarding — surface to a human rather than auto-retrying. For suspended/blocked agent relationships, sellers emit AGENT\_SUSPENDED / AGENT\_BLOCKED instead (those codes carry recovery: terminal directly).

    The authenticated caller is not authorized for the requested action, or a required signed credential (e.g., a <code>{"governance_context"}</code> token on a spend-commit) is missing, fails verification, or was issued for a different plan, seller, or phase. Seller content or advertising policy denials use <code>{"POLICY_VIOLATION"}</code>; media-buy change-right and current-availability denials use <code>{"ACTION_NOT_ALLOWED"}</code>. Distinct from <code>{"AUTH_MISSING"}</code> (no credentials presented), <code>{"AUTH_INVALID"}</code> (credentials presented but rejected), <code>{"GOVERNANCE_DENIED"}</code> (governance agent denied), <code>{"AGENT_SUSPENDED"}</code> (agent's relationship temporarily paused), and <code>{"AGENT_BLOCKED"}</code> (agent's relationship permanently denied). When the gate that fired is specifically a non-status per-agent provisioning constraint — e.g., the agent is provisioned for sandbox traffic only and the request was against a non-sandbox account — <code>{"error.details"}</code> SHOULD conform to <code>{"error-details/agent-permission-denied.json"}</code> (<code>{"scope: \"agent\""}</code> plus <code>{"reason: \"sandbox_only\""}</code>) so callers can dispatch without parsing prose. Sellers MUST emit <code>{"scope: \"agent\""}</code> only when buyer-agent identity has been established via signed-request derivation or a credential-to-agent mapping in the seller's onboarding record; in all other cases (including bearer credentials not mapped to a specific agent record) sellers MUST return <code>{"PERMISSION_DENIED"}</code> and MUST omit <code>{"error.details.scope"}</code> — emitting the per-agent scope without established identity is a cross-tenant onboarding oracle, and the omit MUST be enforced across every observable channel (response shape, HTTP/A2A/MCP status, headers, side effects, observability, latency parity) per the channel-coverage rules in error-handling.mdx Per-Agent Authorization Gate, mirroring the <code>{"*_NOT_FOUND"}</code> uniform-response rule and <code>{"BILLING_NOT_PERMITTED_FOR_AGENT"}</code>. The <code>{"suspended"}</code> and <code>{"blocked"}</code> per-agent states are NOT carried on this code — sellers MUST emit <code>{"AGENT_SUSPENDED"}</code> / <code>{"AGENT_BLOCKED"}</code> instead, each of which is its own discriminator. Recovery: correctable (call <code>{"check_governance"}</code> to mint a valid token, or contact the seller to resolve the underlying permission); when <code>{"details.reason"}</code> is present the rejection is terminal-pending-onboarding — the agent MUST surface to a human at the buyer rather than auto-retrying, since the agent cannot unilaterally extend its sandbox-only provisioning.
  </Accordion>

  <a id="error-code-pixel-tracker-lossy-downgrade" />

  <Accordion title="PIXEL_TRACKER_LOSSY_DOWNGRADE — correctable">
    **Suggested action:** advisory — emitted alongside the v1 downgrade emission: SDK collapsed a pixel\_tracker asset to v1 <code>{"{asset_type: url, url_type: tracker_pixel}"}</code> for a seller that doesn't support pixel\_tracker natively. The URL still fires; what's lost is in <code>{"error.details.lost_fields"}</code> (event variant, method:js execution context, or custom event timing). Buyer decision: accept the loss (most counter pixels survive), or fail the buy and route to a 3.1-capable seller. Non-fatal — do not auto-retry

    Non-fatal advisory raised when a 3.1 buyer SDK downgrades a <code>{"pixel_tracker"}</code> asset to the v1 <code>{"{asset_type: url, url_type: tracker_pixel}"}</code> shape for a 3.0.x seller that doesn't recognize the new asset type. The URL is still emitted on the wire and the seller will fire it as a tracker pixel; what's lost is the event/method discrimination.

    Downgrade rules (normative):

    * <code>{"event: impression"}</code> + <code>{"method: img"}</code> → no loss; emit as <code>{"{asset_type: url, url_type: tracker_pixel, url, asset_id: impression_tracker}"}</code>
    * <code>{"event: viewable_mrc_50"}</code> / <code>{"viewable_mrc_100"}</code> / <code>{"viewable_video_50"}</code> / <code>{"audible_video_complete"}</code> → emit with <code>{"asset_id: viewability_tracker"}</code>; advisory <code>{"lost_event: <variant>"}</code> (specific viewability variant collapses to a single v1 slot)
    * <code>{"event: click"}</code> → emit with <code>{"asset_id: click_tracker"}</code>; no meaningful loss
    * <code>{"event: custom, custom_event_name: X"}</code> → emit with <code>{"asset_id: impression_tracker"}</code> (default tracker\_pixel fires on impression); advisory <code>{"lost_event: \"custom\""}</code>, <code>{"lost_custom_event_name: X"}</code> (custom event timing collapses to impression timing)
    * <code>{"method: js"}</code> → emit unchanged shape (url, url\_type:tracker\_pixel); advisory <code>{"lost_method: \"js\""}</code> (v1 seller will fire as HTTP GET; the URL is hit and any counter-based measurement increments, but the response body won't execute as JS — measurement that depends on JS execution, e.g., OMID-style verification, viewability observers, cross-domain cookie setters, won't work. Simple counter pixels still work.)

    Surface: SDK that performs the downgrade MUST augment the response's <code>{"errors[]"}</code> with <code>{"source: \"sdk\""}</code>, <code>{"sdk_id"}</code>, <code>{"code: \"PIXEL_TRACKER_LOSSY_DOWNGRADE\""}</code>, <code>{"field"}</code> pointing at the affected manifest asset path, and <code>{"error.details"}</code> SHOULD carry <code>{"{ asset_id, original_event, original_method, original_custom_event_name (if present), downgrade_target: \"url+tracker_pixel\", lost_fields: [<list>] }"}</code>. One advisory per downgraded asset; SDKs SHOULD NOT collapse multiple downgrades into a single advisory entry — per-asset details let the buyer's measurement-plan owner decide whether each loss is tolerable.

    Recovery: warning — non-fatal, no retry. Buyer-side decision: accept the loss (most simple counter pixels survive), or fail the buy and route to a 3.1-capable seller. Seller-side fix: upgrade to 3.1 and accept <code>{"pixel_tracker"}</code> natively.
  </Accordion>

  <a id="error-code-pixel-tracker-upgrade-inferred" />

  <Accordion title="PIXEL_TRACKER_UPGRADE_INFERRED — correctable">
    **Suggested action:** advisory — emitted when a 3.1 SDK upgrades a v1 url+tracker\_pixel asset to pixel\_tracker by inferring event and method from asset\_id conventions. The inference may not match the buyer's original intent; check <code>{"error.details.inferred_event"}</code> / <code>{"inferred_method"}</code> and re-prompt the seller for explicit values if precise measurement matters. Non-fatal — do not auto-retry

    Non-fatal advisory raised when a 3.1 buyer SDK upgrades a v1 <code>{"{asset_type: url, url_type: tracker_pixel}"}</code> to a <code>{"pixel_tracker"}</code> asset by INFERRING the event and method from the v1 asset\_id and conventional defaults. The inference is structural — the SDK doesn't have explicit event/method values, only the v1 asset\_id hint and <code>{"url_type: tracker_pixel"}</code> (which implies <code>{"method: img"}</code> by default).

    Inference rules (normative):

    * <code>{"asset_id: impression_tracker"}</code> → <code>{"event: impression, method: img"}</code>
    * <code>{"asset_id: viewability_tracker"}</code> → <code>{"event: viewable_mrc_50, method: img"}</code> (50% is the most common default; specific viewability variant cannot be recovered from v1 shape)
    * <code>{"asset_id: click_tracker"}</code> → <code>{"event: click, method: img"}</code>
    * <code>{"asset_id: <other>"}</code> → <code>{"event: custom, custom_event_name: <original asset_id>, method: img"}</code>

    Surface: SDK MUST augment the response's <code>{"errors[]"}</code> with <code>{"code: \"PIXEL_TRACKER_UPGRADE_INFERRED\""}</code>, <code>{"field"}</code> pointing at the upgraded asset path, and <code>{"error.details"}</code> SHOULD carry <code>{"{ asset_id, inferred_event, inferred_method, inference_basis: \"asset_id_convention\" \u007c \"default\" }"}</code>. Buyer agents reading the response can re-prompt the seller for explicit values if precise measurement matters.

    Recovery: warning — non-fatal, no retry. Seller-side: upgrade emit path to ship pixel\_tracker shape directly when 3.1-capable; until then, conventional asset\_id values give the SDK enough signal to upgrade without losing critical semantics.
  </Accordion>

  <a id="error-code-place-target-unavailable" />

  <Accordion title="PLACE_TARGET_UNAVAILABLE — correctable">
    **Suggested action:** resolve the pinned value against the current catalog, review any replacement, and submit an intentional package targeting update

    A place identifier previously accepted and pinned on a package can no longer be executed. This is a nonfatal resource-state error returned in get\_media\_buys.errors\[] alongside the affected buy. error.field MUST point to the exact media\_buys\[N].packages\[M].targeting\_overlay.geo\_places\[\_exclude]\[A].values\[V] response path. error.details MUST include media\_buy\_id, package\_id, system, system\_version, country, place\_type, and value. The seller MUST preserve and echo the pinned target rather than silently changing geography. Recovery: correctable (look up the value through the declared resolver at the current catalog version and submit an intentional targeting update).
  </Accordion>

  <a id="error-code-plan-not-found" />

  <Accordion title="PLAN_NOT_FOUND — correctable">
    **Suggested action:** verify plan\_id via sync\_plans, or register the plan first

    Referenced governance plan does not exist or is not accessible to the requesting agent. Recovery: correctable (verify plan\_id via sync\_plans, or register the plan first). Sellers MUST return this code uniformly for any plan\_id not accessible to the calling account — never distinguish 'exists but unauthorized' from 'does not exist', which would enable cross-tenant enumeration of governance plans.
  </Accordion>

  <a id="error-code-policy-violation" />

  <Accordion title="POLICY_VIOLATION — correctable">
    **Suggested action:** review policy requirements in the error details

    Request violates the seller's content or advertising policies. Recovery: correctable (review policy requirements in the error details).
  </Accordion>

  <a id="error-code-private-field-in-public-placement" />

  <Accordion title="PRIVATE_FIELD_IN_PUBLIC_PLACEMENT — correctable">
    **Suggested action:** seller-side fix needed: remove private operational fields (<code>{"visibility"}</code>, <code>{"source"}</code>, <code>{"origin"}</code>, <code>{"delivery_mappings"}</code>, or similar) from public placement objects. Consumers MUST fail closed for the affected placement and alert operators; do not echo private field values in logs or error details

    Fatal producer-side error raised when a public placement object (<code>{"Product.placements[]"}</code> in <code>{"get_products"}</code> or <code>{"placements[]"}</code> in adagents.json) exposes seller-private operational fields such as <code>{"visibility"}</code>, <code>{"source"}</code>, <code>{"origin"}</code>, or <code>{"delivery_mappings"}</code>. This is a private-data leak, not an ordinary syntactic mismatch. Consumers that detect it MUST fail closed for that placement and surface this code so monitoring can alarm on the leak specifically instead of burying it under generic schema validation. <code>{"error.field"}</code> SHOULD point at the offending placement path and <code>{"error.details"}</code> SHOULD carry <code>{"{ placement_id, leaked_fields: [<field names>] }"}</code> without echoing private field values. Recovery: correctable but seller-side — remove private operational fields from the public placement surface and keep delivery mappings in seller-internal systems.
  </Accordion>

  <a id="error-code-product-expired" />

  <Accordion title="PRODUCT_EXPIRED — correctable">
    **Suggested action:** re-discover with get\_products to find current inventory

    The seller still recognizes one or more configured product IDs as issued to the authenticated account and referenced discovery/refinement lineage, and they have passed their expires\_at timestamps. Sellers are not required to retain expiry tombstones indefinitely; an ID that is no longer resolvable, or is inaccessible to this caller because it belongs to another account or lineage, uses PRODUCT\_NOT\_FOUND. This distinction MUST NOT become a cross-tenant existence oracle. Recovery: correctable (re-discover through list\_products, request\_proposals, or the get\_products compatibility facade to find current inventory).
  </Accordion>

  <a id="error-code-product-not-found" />

  <Accordion title="PRODUCT_NOT_FOUND — correctable">
    **Suggested action:** remove invalid IDs and retry, or re-discover with get\_products

    One or more referenced product IDs are unknown or are not resolvable within the authenticated account and configured-offer lineage. A caller-authorized configured ID that is still recognized as expired uses PRODUCT\_EXPIRED; once no expiry tombstone remains, or whenever the ID belongs to another account or lineage, PRODUCT\_NOT\_FOUND applies. Sellers MUST NOT reveal cross-tenant product existence through error choice. Recovery: correctable (remove invalid IDs and retry, or re-discover with get\_products).
  </Accordion>

  <a id="error-code-product-unavailable" />

  <Accordion title="PRODUCT_UNAVAILABLE — correctable">
    **Suggested action:** choose a different product

    The requested product is sold out or no longer available. Recovery: correctable (choose a different product).
  </Accordion>

  <a id="error-code-proposal-expired" />

  <Accordion title="PROPOSAL_EXPIRED — correctable">
    **Suggested action:** call request\_proposals and finalize a fresh proposal, or re-discover and finalize through legacy get\_products

    A referenced proposal ID has passed its expires\_at timestamp. For a committed proposal, the inventory hold has lapsed. Recovery: correctable (call request\_proposals and finalize a fresh proposal, or re-discover and finalize through the legacy get\_products facade).
  </Accordion>

  <a id="error-code-proposal-not-committed" />

  <Accordion title="PROPOSAL_NOT_COMMITTED — correctable">
    **Suggested action:** finalize the draft through refine\_proposals, or through the legacy get\_products refine action

    The referenced proposal has proposal\_status 'draft' and cannot be accepted into a media buy. Recovery: correctable (finalize it through refine\_proposals, or through the legacy get\_products refine action).
  </Accordion>

  <a id="error-code-proposal-not-found" />

  <Accordion title="PROPOSAL_NOT_FOUND — correctable">
    **Suggested action:** request and finalize a fresh proposal, then retry

    The referenced proposal\_id is not recognized by the seller — it belongs to a different tenant, was never issued, or was evicted from the seller's session cache before consumption. Distinct from <code>{"PROPOSAL_EXPIRED"}</code> (a known proposal whose <code>{"expires_at"}</code> window has passed) and <code>{"PROPOSAL_NOT_COMMITTED"}</code> (a known proposal still in <code>{"draft"}</code>). Recovery: correctable (request a fresh proposal, finalize it, then retry accept\_proposal; 3.x compatibility callers retry create\_media\_buy).
  </Accordion>

  <a id="error-code-provenance-claim-contradicted" />

  <Accordion title="PROVENANCE_CLAIM_CONTRADICTED — correctable">
    **Suggested action:** revise the provenance claim to match the verifier's observation or replace the creative; auto-retry without correction will not pass

    Seller invoked a governance agent from <code>{"creative_policy.accepted_verifiers"}</code> via <code>{"get_creative_features"}</code> and the verifier's result contradicts the buyer's provenance claim - e.g., buyer claims <code>{"digital_source_type: digital_capture"}</code> but the AI-detection feature returns <code>{"ai_generated: true"}</code> above the seller's confidence threshold. Distinct from the <code>{"PROVENANCE_*_MISSING"}</code> family (structural absence) by being an active refutation. <code>{"error.details"}</code> SHOULD be limited to the audit-safe allowlist <code>{"{ agent_url, feature_id, claimed_value, observed_value, confidence }"}</code>; sellers MUST NOT forward arbitrary verifier extension fields, <code>{"detail_url"}</code>, or any verifier response shape that may carry cross-tenant or PII data. When the seller calls a different on-list agent than the buyer nominated (the seller is the verifier-of-record), <code>{"error.details.agent_url"}</code> is the agent the seller actually called and <code>{"error.details.substituted_for"}</code> SHOULD carry the buyer's nominated <code>{"agent_url"}</code> so the buyer can reconcile. Recovery: correctable - buyer revises the provenance claim to match reality (or replaces the creative); auto-retry without correction will not pass.
  </Accordion>

  <a id="error-code-provenance-digital-source-type-missing" />

  <Accordion title="PROVENANCE_DIGITAL_SOURCE_TYPE_MISSING — correctable">
    **Suggested action:** set provenance.digital\_source\_type to a value from the digital-source-type enum and resubmit

    Seller's <code>{"creative_policy.provenance_requirements.require_digital_source_type"}</code> is true and the submitted creative's resolved provenance (after inheritance) has no <code>{"digital_source_type"}</code> value, or has it set to null. Distinct from <code>{"PROVENANCE_REQUIRED"}</code> (no provenance object at all) - provenance is present, just missing this specific field. Recovery: correctable (set <code>{"provenance.digital_source_type"}</code> to a value from the <code>{"digital-source-type"}</code> enum and resubmit). <code>{"error.field"}</code> MUST point at the resolved provenance path that was inspected (e.g., <code>{"creatives[0].creative_manifest.provenance.digital_source_type"}</code>).
  </Accordion>

  <a id="error-code-provenance-disclosure-missing" />

  <Accordion title="PROVENANCE_DISCLOSURE_MISSING — correctable">
    **Suggested action:** set provenance.disclosure.required and, when true, populate disclosure.jurisdictions

    Seller's <code>{"creative_policy.provenance_requirements.require_disclosure_metadata"}</code> is true and the submitted creative's resolved provenance has no <code>{"disclosure.required"}</code> boolean, or <code>{"disclosure.required"}</code> is true with no <code>{"disclosure.jurisdictions"}</code> entries. Recovery: correctable (set <code>{"provenance.disclosure.required"}</code> and, when true, populate <code>{"disclosure.jurisdictions"}</code>). <code>{"error.field"}</code> MUST point at <code>{"provenance.disclosure"}</code> (e.g., <code>{"creatives[0].creative_manifest.provenance.disclosure"}</code>).
  </Accordion>

  <a id="error-code-provenance-embedded-missing" />

  <Accordion title="PROVENANCE_EMBEDDED_MISSING — correctable">
    **Suggested action:** attach at least one embedded\_provenance entry from a supported provider and resubmit

    Seller's <code>{"creative_policy.provenance_requirements.require_embedded_provenance"}</code> is true and the submitted creative's resolved provenance has no <code>{"embedded_provenance"}</code> array, or has it as an empty array. Used in pipelines where sidecar <code>{"c2pa.manifest_url"}</code> is stripped by intermediaries and the seller requires content-stream-resilient provenance. Recovery: correctable (attach at least one <code>{"embedded_provenance"}</code> entry from a supported provider and resubmit, optionally with a <code>{"verify_agent"}</code> pointer matching one of the seller's <code>{"creative_policy.accepted_verifiers"}</code>). <code>{"error.field"}</code> MUST point at <code>{"provenance.embedded_provenance"}</code> on the resolved manifest.
  </Accordion>

  <a id="error-code-provenance-required" />

  <Accordion title="PROVENANCE_REQUIRED — correctable">
    **Suggested action:** attach a provenance object - at minimum digital\_source\_type - and resubmit

    Seller's <code>{"creative_policy.provenance_required"}</code> is true and the submitted creative has no <code>{"provenance"}</code> object on the manifest, on the creative-asset, or on any individual asset. Distinct from <code>{"CREATIVE_REJECTED"}</code> (generic creative-review failure) by being narrowly about provenance presence. Recovery: correctable (attach a provenance object - at minimum <code>{"digital_source_type"}</code> - and resubmit). <code>{"error.field"}</code> MUST point at the path where provenance was expected (e.g., <code>{"creatives[0].creative_manifest"}</code>).
  </Accordion>

  <a id="error-code-provenance-synthetic-depiction-missing" />

  <Accordion title="PROVENANCE_SYNTHETIC_DEPICTION_MISSING — correctable">
    **Suggested action:** assess the creative, set provenance.synthetic\_depiction to true or false, and resubmit

    Seller's <code>{"creative_policy.provenance_requirements.require_synthetic_depiction"}</code> is true and the submitted creative's resolved provenance (after inheritance) has no <code>{"synthetic_depiction"}</code> boolean. Both <code>{"true"}</code> and <code>{"false"}</code> satisfy the requirement; absence means unassessed. Distinct from <code>{"PROVENANCE_REQUIRED"}</code> (no provenance object at all) and from <code>{"PROVENANCE_CLAIM_CONTRADICTED"}</code> (an independent verifier actively refuted a declared value). Recovery: correctable (assess the creative, set <code>{"provenance.synthetic_depiction"}</code> to true or false, and resubmit). <code>{"error.field"}</code> MUST point at the resolved <code>{"provenance.synthetic_depiction"}</code> path. The declaration does not establish consent, legality, or verification.
  </Accordion>

  <a id="error-code-provenance-verifier-not-accepted" />

  <Accordion title="PROVENANCE_VERIFIER_NOT_ACCEPTED — correctable">
    **Suggested action:** replace verify\_agent.agent\_url with one from the seller's published accepted\_verifiers, drop verify\_agent if the embedding is self-verifiable, or re-embed with a verifier the seller accepts

    Buyer attached a <code>{"verify_agent.agent_url"}</code> on <code>{"embedded_provenance[]"}</code> or <code>{"watermarks[]"}</code> that does not match (canonicalized per /docs/reference/url-canonicalization: lowercase scheme and host, strip default port, normalize path dot-segments) any entry in the seller's <code>{"creative_policy.accepted_verifiers[].agent_url"}</code>. The seller does not call buyer-asserted endpoints outside its allowlist; this is the cross-check that closes the buyer-controlled-URL trust gap. <code>{"error.field"}</code> MUST point at the offending <code>{"verify_agent.agent_url"}</code> path; <code>{"error.details"}</code> SHOULD include a reference to the product whose <code>{"creative_policy.accepted_verifiers"}</code> the buyer should consult (the buyer already has this from <code>{"get_products"}</code>). Recovery: correctable (replace <code>{"verify_agent.agent_url"}</code> with one from the seller's published <code>{"accepted_verifiers"}</code>, drop the <code>{"verify_agent"}</code> entirely if the embedding is self-verifiable, or re-embed evidence using a verifier the seller accepts).
  </Accordion>

  <a id="error-code-rate-limited" />

  <Accordion title="RATE_LIMITED — transient">
    **Suggested action:** wait top-level error.retry\_after seconds when present, then retry

    Request rate exceeded. Sellers SHOULD populate top-level <code>{"error.retry_after"}</code> with the integer number of seconds to wait. Recovery: transient (wait <code>{"error.retry_after"}</code> seconds when present, then retry).
  </Accordion>

  <a id="error-code-read-only-scope" />

  <Accordion title="READ_ONLY_SCOPE — correctable">
    **Suggested action:** use a non-mutating alternative, or surface to the operator to request a scope that permits mutation

    The caller's scope is read-only; the invoked task would mutate state and was rejected. Distinct from <code>{"SCOPE_INSUFFICIENT"}</code> (task not in scope at all) — the task is in some scopes this seller supports, just not this caller's. Recovery: correctable but not agent-autonomous — use a non-mutating alternative, or surface to the operator to request a scope that permits mutation.
  </Accordion>

  <a id="error-code-reference-not-found" />

  <Accordion title="REFERENCE_NOT_FOUND — correctable">
    **Suggested action:** verify the referenced identifier exists and is accessible to the caller

    Generic fallback for a referenced identifier, grant, session, or other resource that does not exist or is not accessible by the caller. Use when no resource-specific not-found code applies (e.g., property lists, content standards, rights grants, SI offerings, proposals, catalogs, event sources, collection lists, brands, individual properties). Typed parameters that lack a dedicated standard code MUST also use REFERENCE\_NOT\_FOUND rather than minting a custom \*\_NOT\_FOUND code. See 'Uniform response for inaccessible references' in error-handling.mdx for the full MUST list. Recovery: correctable. Summary of the uniform-response MUST: sellers MUST return the same response for 'exists but the caller lacks access' as for 'does not exist' across every observable channel — error.code/message/field/details (message MUST be generic; error.field MUST be identical across both cases on typed parameters); HTTP status, A2A task.status.state, and MCP isError; response headers (ETag, Cache-Control, per-type rate-limit buckets, CDN tags); side effects (webhook/audit writes, background-job enqueues, per-type quota counters, DB-shard routing); and observability (logs, APM spans, third-party error telemetry like Sentry/Datadog). Sellers MUST perform the same resolution-and-authorization work on both paths (resolve-then-authorize; on true-miss still run an authorization decision of equivalent shape against an empty principal set so authorizer latency is not a side channel). Cache population MUST NOT be gated on authorization. Polymorphism is evaluated against the tool-schema's declared parameter shape before any lookup, and a tool's declared shape MUST be identical across all callers.
  </Accordion>

  <a id="error-code-requote-required" />

  <Accordion title="REQUOTE_REQUIRED — correctable">
    **Suggested action:** refine accepted\_proposal\_id into an amendment and apply it through accept\_proposal, or keep control\_media\_buy inside the accepted envelope; 3.1 compatibility callers must adjust or rediscover

    A control\_media\_buy request, or the 3.x update\_media\_buy facade, would exceed the accepted commercial envelope. The seller is declining the requested shape at the current terms. Distinct from TERMS\_REJECTED (measurement) and POLICY\_VIOLATION (content). Sellers SHOULD populate error.details.envelope\_field with the field path(s) that breached the envelope. AdCP 3.2 callers refine the MediaBuy's accepted\_proposal\_id to obtain a typed amendment; legacy 3.1 callers adjust the update, rediscover terms, or create a separate buy.
  </Accordion>

  <a id="error-code-scope-insufficient" />

  <Accordion title="SCOPE_INSUFFICIENT — correctable">
    **Suggested action:** the agent cannot broaden its own scope - surface to the operator rather than auto-retry

    The authenticated caller is not authorized for the invoked task — the task is not in the caller's <code>{"allowed_tasks"}</code> for this account (discoverable via the <code>{"authorization"}</code> object on sync\_accounts / list\_accounts responses). Distinct from <code>{"PERMISSION_DENIED"}</code> (generic authz failure, often credential-shaped) by being narrowly about task-level scope. Sellers SHOULD populate <code>{"error.details.introspection_hint"}</code> pointing at where the caller can re-read its scope (strawman: <code>{"{ task: 'list_accounts', account: {...} }"}</code>). Recovery: correctable in the sense that the request can be re-sent after the scope is broadened, but the agent cannot broaden its own scope — this requires operator intervention, and agents SHOULD surface rather than auto-retry.
  </Accordion>

  <a id="error-code-service-unavailable" />

  <Accordion title="SERVICE_UNAVAILABLE — transient">
    **Suggested action:** retry with exponential backoff

    Seller service is temporarily unavailable. Retry with exponential backoff. Recovery: transient.
  </Accordion>

  <a id="error-code-session-not-found" />

  <Accordion title="SESSION_NOT_FOUND — correctable">
    **Suggested action:** initiate a new session via si\_initiate\_session

    SI session ID is invalid, expired, or does not exist. Recovery: correctable (initiate a new session via si\_initiate\_session).
  </Accordion>

  <a id="error-code-session-terminated" />

  <Accordion title="SESSION_TERMINATED — correctable">
    **Suggested action:** initiate a new session via si\_initiate\_session

    SI session has already been terminated and cannot accept further messages. Recovery: correctable (initiate a new session via si\_initiate\_session).
  </Accordion>

  <a id="error-code-signal-not-found" />

  <Accordion title="SIGNAL_NOT_FOUND — correctable">
    **Suggested action:** verify signal\_id via get\_signals, or confirm the signal is available from this agent

    Referenced signal does not exist in the agent's catalog. Recovery: correctable (verify signal\_ref via get\_signals, or confirm the signal is available from this agent). Sellers MUST return this code uniformly for any signal\_ref not accessible to the calling account — never distinguish 'exists but unauthorized' from 'does not exist', which would enable cross-tenant enumeration.
  </Accordion>

  <a id="error-code-signal-targeting-incompatible" />

  <Accordion title="SIGNAL_TARGETING_INCOMPATIBLE — correctable">
    **Suggested action:** assign the creative to a package whose signal targeting matches the creative's signal\_condition, or rebuild the creative for the package's condition; match on shared signal\_ref identity (compare signal\_agent\_segment\_id exactly when both carry it, else categorical signal\_ref + value)

    A creative carrying a signal\_condition (from build\_creative signal\_conditions fan-out, #5240) was assigned to a package whose signal targeting is incompatible — e.g. a sun creative routed to a rain-targeted package. The trafficking-compatibility invariant: a creative built FOR one signal condition MUST NOT serve into a package targeting an incompatible condition. Enforced reject-at-trafficking on the sales side (create\_media\_buy / sync\_creatives), NOT at build\_creative (per #5280, signal pointers are advisory at the build layer; enforcement lives at the trafficking boundary). Compatibility is matched on shared signal\_ref identity: when both sides carry signal\_agent\_segment\_id, compare the opaque handle exactly; when both carry only categorical \{signal\_id,value}, compare signal\_ref + value-set semantics; equal categorical labels from DIFFERENT providers are NOT compatible absent an explicit equivalence mechanism; when one side has a segment handle and the other only a categorical value, the seller MAY accept only if it can resolve both to the same provider-issued segment, else reject/warn. For value\_type:numeric the comparison is range-overlap (WG-open: range-overlap vs exact-match — see RFC #5240 open decisions). error.field SHOULD point at the offending assignment path (e.g. packages\[N].creative\_assignments\[M] or creatives\[N]); error.details SHOULD carry the creative's signal\_condition and the package's incompatible signal targeting so the buyer can re-route. Distinct from SIGNAL\_NOT\_FOUND (signal unknown/inaccessible) by being a compatibility mismatch between a known creative condition and a known package condition. Recovery: correctable (assign the creative to a package whose signal targeting matches its signal\_condition, or rebuild for the package's condition).
  </Accordion>

  <a id="error-code-signed-response-envelope-expired" />

  <Accordion title="SIGNED_RESPONSE_ENVELOPE_EXPIRED — transient">
    **Suggested action:** re-invoke the designated task (verify\_brand\_claim or verify\_brand\_claims) to obtain a freshly signed response with a current exp window

    The <code>{"signed_response.payload.exp"}</code> timestamp is at or past the current time after applying the verifier's clock-skew tolerance. The signed envelope was valid when issued but the verification window has closed. Raised by verifiers consuming a designated-task signed response (<code>{"verify_brand_claim"}</code> / <code>{"verify_brand_claims"}</code>) during step 7 of the [response-signing verifier checklist](/docs/building/by-layer/L1/security#verifier-checklist-responses). Online verifiers MUST reject expired envelopes; audit verifiers MAY verify after <code>{"exp"}</code> as historical evidence that the brand-agent signed the payload during the stated <code>{"iat"}</code>/<code>{"exp"}</code> window, but MUST NOT treat the result as current truth. Distinct from <code>{"STALE_RESPONSE"}</code> (cache-staleness advisory on a populated success payload) by being a cryptographic freshness failure on a signed response envelope. Recovery: transient (re-invoke the designated task to obtain a freshly signed response with a current <code>{"exp"}</code> window).
  </Accordion>

  <a id="error-code-signed-response-request-hash-mismatch" />

  <Accordion title="SIGNED_RESPONSE_REQUEST_HASH_MISMATCH — correctable">
    **Suggested action:** re-invoke the designated task with the intended request parameters — the signed response's request\_hash does not match the verifier's recomputed hash of the actual request; if the mismatch persists across retries, investigate JCS request-binding canonicalization between caller and responder

    The <code>{"signed_response.payload.request_hash"}</code> does not match the verifier's recomputed SHA-256 hash of the canonical request-binding object <code>{"{ task, brand_domain, agent_url, caller_identity, request }"}</code> for the actual request sent. Raised during step 8 of the [response-signing verifier checklist](/docs/building/by-layer/L1/security#verifier-checklist-responses). This indicates either a replay of a signed response from a different request, a JCS request-binding canonicalization divergence between signer and verifier, or payload tampering. Verifiers MUST reject the envelope when the recomputed hash does not byte-match the signed <code>{"request_hash"}</code>. <code>{"error.details"}</code> SHOULD carry <code>{"expected_request_hash"}</code> (the verifier's recomputed value) when safe to disclose — the hash binds the response to the exact request that produced it, and divergence is the signal that the binding has been broken. Recovery: correctable (re-invoke the designated task with the intended request parameters; if the mismatch persists across retries, investigate JCS request-binding canonicalization between the caller and the responding agent).
  </Accordion>

  <a id="error-code-signed-response-tenant-mismatch" />

  <Accordion title="SIGNED_RESPONSE_TENANT_MISMATCH — correctable">
    **Suggested action:** verify the request targeted the correct brand domain and agent\_url, then re-invoke; if the mismatch persists, the responding agent's server-side tenant resolution may be misconfigured

    The <code>{"signed_response.payload.brand_domain"}</code> does not match the verifier's resolved or expected brand tenant for this verification call. Raised during step 9 of the [response-signing verifier checklist](/docs/building/by-layer/L1/security#verifier-checklist-responses). The responding brand agent derives <code>{"brand_domain"}</code> from server-side tenant resolution, not from caller-supplied request fields (per the response-signing profile in security.mdx), so a mismatch indicates cross-tenant replay, a multi-brand agent routing error, or a mismatch between the verifier's tenant resolution and the responder's. Distinct from <code>{"SIGNED_RESPONSE_REQUEST_HASH_MISMATCH"}</code> (request-binding divergence) by being narrowly about the tenant identity — <code>{"brand_domain"}</code> is a field inside the signed payload that the responder derives independently, not an echo of any caller-supplied value. Recovery: correctable (verify that the request targeted the correct brand domain and agent; re-invoke with the correct brand reference if the request was mis-routed; if the mismatch persists, the responding agent's server-side tenant resolution may be misconfigured).
  </Accordion>

  <a id="error-code-source-access-failed" />

  <Accordion title="SOURCE_ACCESS_FAILED — correctable">
    **Suggested action:** error.field source.locator/source.segment\_ref: fix the reference; error.field source: grant the seller's declared consumer identity and retry; no error.field: vendor outage, retry with backoff

    Seller could not read an external audience source on sync\_audiences (experimental, media\_buy.audience\_activation). Per-audience: surfaces as action: failed with this code in the audience's errors array. The seller cannot reliably distinguish a revoked grant from an expired one from a transient vendor outage — all three observables are a failed read — so error.field distinguishes what the buyer can act on: 'source.locator' or 'source.segment\_ref' means the reference does not resolve (changed request needed); 'source' means access denied (establish or re-grant access to the seller's declared consumer identity, then retry); absence of error.field indicates a vendor-side failure (retry with backoff, no buyer action). On an already-ready audience a failed re-read MUST NOT change audience status — membership stays frozen at the last successful read and source.access\_status reports 'unavailable'. Recovery: correctable (fix the reference or grant per error.field; vendor outages without error.field are transient and retry with backoff).
  </Accordion>

  <a id="error-code-stale-response" />

  <Accordion title="STALE_RESPONSE — transient">
    **Suggested action:** advisory — emitted alongside a populated payload that was served from cache past the seller's freshness target because an upstream or sub-agent was unreachable. The response is usable; treat as non-fatal. Inspect <code>{"error.details.cache_age_seconds"}</code> to decide whether to immediately retry for fresh data or accept the cached value; the seller's own service is healthy, so retry is safe (it does not amplify the upstream failure)

    Non-fatal advisory raised when the seller's live fetch to an upstream or sub-agent failed (timeout, connection error, downstream 5xx) and the response payload was satisfied from a cached prior result that is past the seller's freshness target for this surface. Emitted **alongside** a populated success payload — the caller's request still completes from a usable cache hit; this code tells downstream consumers that the data is older than the seller would normally serve.

    Distinct from <code>{"SERVICE_UNAVAILABLE"}</code> (seller's own service is down, no payload — transient, retry-with-backoff) by signalling **graceful degradation**: the seller's own service is fine, but one of its dependencies is currently unreachable and the seller chose to honor the request from cache rather than return empty. Sellers MUST emit <code>{"STALE_RESPONSE"}</code> ONLY when the response payload is non-empty AND derived from a cache entry whose <code>{"cache_age_seconds"}</code> exceeds the surface's freshness target. When no cached entry exists (or the cache hit is within freshness target), sellers MUST NOT emit this code — return the empty-or-fresh response with whatever upstream-failure code applies (e.g., <code>{"SERVICE_UNAVAILABLE"}</code>).

    **Wire placement (normative).** Transport-level success markers stay flipped to success (HTTP 200, MCP <code>{"isError: false"}</code>, A2A <code>{"succeeded"}</code>) — the task ran successfully and produced a response, even if from cache. The advisory rides in <code>{"errors[]"}</code> on the payload and MUST NOT be promoted to <code>{"adcp_error"}</code> on the envelope (envelope-level errors are reserved for the empty-payload failure case per the two-layer model in <code>{"error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model"}</code>). <code>{"error.field"}</code> SHOULD point at the affected payload path (e.g., <code>{"formats"}</code> for <code>{"list_creative_formats"}</code>, <code>{"products"}</code> for <code>{"get_products"}</code>). <code>{"error.details"}</code> SHOULD conform to <code>{"error-details/stale-response.json"}</code> — <code>{"served_from_cache"}</code> (required, always <code>{"true"}</code>), <code>{"cache_age_seconds"}</code> (required), and optionally <code>{"freshness_target_seconds"}</code>, <code>{"upstream"}</code> (the dependency that failed), and <code>{"original_error"}</code> (the underlying failure code/message).

    **Multiple stale upstreams.** When N sub-agents are stale (e.g., a <code>{"list_creative_formats"}</code> registry aggregating from multiple creative agents), the seller SHOULD emit **one <code>{"STALE_RESPONSE"}</code> entry per affected upstream** rather than aggregating — the per-upstream shape mirrors the existing precedent set by <code>{"PIXEL_TRACKER_LOSSY_DOWNGRADE"}</code> (one advisory per downgraded asset) and lets buyer agents reason about which sub-population of the payload is stale. Each entry's <code>{"error.field"}</code> SHOULD narrow to the affected slice (e.g., <code>{"formats"}</code> for formats sourced from the stale upstream).

    Recovery: transient — buyers MUST treat as non-fatal (the response is usable), MAY immediately retry later for fresh data, and SHOULD surface staleness to operators or end users when relevant. <code>{"cache_age_seconds"}</code> is the informational knob for the buyer's own "is this stale enough to bother retrying" policy.
  </Accordion>

  <a id="error-code-terms-rejected" />

  <Accordion title="TERMS_REJECTED — correctable">
    **Suggested action:** adjust the proposed terms and retry, or omit measurement\_terms to accept the product's defaults

    Buyer-proposed measurement\_terms were rejected by the seller. The error details SHOULD identify which specific term was rejected and the seller's acceptable range or supported vendors. Recovery: correctable (adjust the proposed terms and retry, or omit measurement\_terms to accept the product's defaults).
  </Accordion>

  <a id="error-code-unpriceable-output" />

  <Accordion title="UNPRICEABLE_OUTPUT — correctable">
    **Suggested action:** target an output format the transformer prices, or have the seller add a pricing option covering it

    A creative transformer build targets an output capability that no pricing option covers — no transformer.pricing\_options entry has a matching applies\_to\_output\_capability\_ids and none is unscoped. The build is rejected rather than billed at a guessed rate. Recovery: correctable.
  </Accordion>

  <a id="error-code-unsupported-feature" />

  <Accordion title="UNSUPPORTED_FEATURE — correctable">
    **Suggested action:** check get\_adcp\_capabilities and remove unsupported fields

    A requested feature or field is not supported by this seller. When rejecting a <code>{"refine_proposals"}</code> request that uses a typed dimension omitted from an explicit <code>{"proposal_refinement.supported_dimensions"}</code> declaration, the error details SHOULD follow <code>{"error-details/unsupported-refinement-dimension.json"}</code> — <code>{"unsupported_dimension"}</code> names the offending dimension and <code>{"supported_dimensions"}</code> echoes the seller's declaration so the buyer can remove or translate the field without another capability round trip. Recovery: correctable (check get\_adcp\_capabilities and remove unsupported fields).
  </Accordion>

  <a id="error-code-unsupported-granularity" />

  <Accordion title="UNSUPPORTED_GRANULARITY — correctable">
    **Suggested action:** pick a granularity from the product's reporting\_capabilities.windowed\_pull\_granularities (via get\_adcp\_capabilities) and resubmit, or omit time\_granularity to fall back to cumulative date-range pulls

    The requested <code>{"time_granularity"}</code> on <code>{"get_media_buy_delivery"}</code> is not in the product's declared <code>{"reporting_capabilities.windowed_pull_granularities"}</code>. Distinct from <code>{"UNSUPPORTED_FEATURE"}</code> (generic capability mismatch) by being narrowly about reporting-window granularity — the buyer asked for hourly pull-recovery on a product that only honors daily pulls, for example. Sellers MAY echo the declared set in <code>{"error.details.supported_granularities"}</code> when the caller is authorized to read the product's reporting capabilities — the same set is already available via <code>{"get_adcp_capabilities"}</code>, so the echo is a convenience, not load-bearing. Sellers MUST NOT echo a granularity set the caller could not otherwise read (per-product capability views vary by buyer entitlement). The <code>{"error.field"}</code> SHOULD point at <code>{"time_granularity"}</code>. Buyers that need higher-frequency recovery than the seller's pull set supports MUST rely on the webhook channel as primary at that frequency — the seller's <code>{"available_reporting_frequencies"}</code> may legitimately exceed <code>{"windowed_pull_granularities"}</code> (e.g., a stream-tap webhook on Kafka with warehouse pulls only at daily). Recovery: correctable (re-issue at a granularity in the declared set, or omit <code>{"time_granularity"}</code> to fall back to cumulative date-range pulls).
  </Accordion>

  <a id="error-code-unsupported-provisioning" />

  <Accordion title="UNSUPPORTED_PROVISIONING — correctable">
    **Suggested action:** re-issue with the entry shape the seller supports — <code>{"account: {account_id: ...}"}</code> for settings-update sellers with account-id namespaces, or <code>{"brand+operator+billing"}</code> for provisioning sellers; check seller documentation or capability declaration for which modes are implemented

    The seller does not support the <code>{"sync_accounts"}</code> mode the entry requested. Returned per-entry in the <code>{"sync_accounts"}</code> response when (a) an entry keyed by the natural-key trio (<code>{"brand"}</code> + <code>{"operator"}</code> + <code>{"billing"}</code>) is sent to a seller that does not provision accounts via AdCP — typical for account-id namespaces where accounts are pre-provisioned out of band or discovered via <code>{"list_accounts"}</code>; or (b) an entry keyed by <code>{"account"}</code> (AccountRef) is sent to a seller that has not implemented the settings-update mode. Distinct from <code>{"UNSUPPORTED_FEATURE"}</code> (generic capability mismatch) by being narrowly about which of the two <code>{"sync_accounts"}</code> modes the seller implements. The two modes are mutually exclusive per-entry — the seller MUST NOT silently downgrade or upgrade between them. Sellers MAY declare which modes they implement via <code>{"get_adcp_capabilities"}</code> (forward-looking — capability declaration shape is open). Recovery: correctable (re-issue with the entry shape the seller supports; for account-id namespaces that expose settings updates, that means <code>{"account: {account_id: ...}"}</code> entries; for sellers that only provision via natural key that means the flat <code>{"brand+operator+billing"}</code> shape). The <code>{"error.field"}</code> SHOULD point at the entry index where the unsupported shape was found.
  </Accordion>

  <a id="error-code-validation-error" />

  <Accordion title="VALIDATION_ERROR — correctable">
    **Suggested action:** review error details and fix field values

    Request contains invalid field values or violates business rules beyond schema validation. Recovery: correctable (review error details and fix field values).
  </Accordion>

  <a id="error-code-vast-parse-failed" />

  <Accordion title="VAST_PARSE_FAILED — correctable">
    **Suggested action:** inspect error.details.reason (not\_xml, no\_vast\_root, no\_ad, no\_media\_file), fix the VAST document, and resubmit

    A submitted <code>{"vast"}</code> asset failed document-level validation: the inline <code>{"content"}</code> (or the document fetched from <code>{"url"}</code>) is not well-formed XML, has no <code>{"<VAST>"}</code> root element, contains no <code>{"<Ad>"}</code> element, or an <code>{"<InLine>"}</code> linear creative carries no <code>{"<MediaFile>"}</code>. Returned by sellers that declare <code>{"creative_specs.vast_validation"}</code> of <code>{"document"}</code> or <code>{"wrapper"}</code>; sellers at the default <code>{"structural"}</code> level do not inspect the VAST document and MUST NOT return this code. Distinct from <code>{"VALIDATION_ERROR"}</code> (manifest-level format validation): the manifest was structurally valid, the VAST document inside it was not. Sellers SHOULD set <code>{"error.field"}</code> to the offending asset path and SHOULD populate <code>{"error.details.reason"}</code> with one of <code>{"not_xml"}</code>, <code>{"no_vast_root"}</code>, <code>{"no_ad"}</code>, <code>{"no_media_file"}</code>. Unresolved ad-server macros in URLs (<code>{"[MACRO]"}</code>, <code>{"${MACRO}"}</code>, <code>{"{UNIVERSAL_MACRO}"}</code>) are opaque tokens, not parse failures. Recovery: correctable (fix the VAST document and resubmit).
  </Accordion>

  <a id="error-code-vast-version-mismatch" />

  <Accordion title="VAST_VERSION_MISMATCH — correctable">
    **Suggested action:** inspect error.details.mismatch\_reason and the corresponding acceptance-set or observed-document fields; select a compatible source representation or correct the offending VAST document

    A submitted <code>{"vast"}</code> asset is version-incompatible when its exact <code>{"vast_version"}</code> is absent from the intersection of the selected product format option's <code>{"params.vast_versions"}</code> and the seller's <code>{"execution.creative_specs.vast_versions"}</code>, or when an inspected document violates its applicable VAST version rule. Modern <code>{"error.details"}</code> MUST conform to <code>{"error-details/vast-version-mismatch.json"}</code>: acceptance failures carry <code>{"mismatch_reason: asset_outside_acceptance"}</code>, <code>{"asset_vast_version"}</code>, <code>{"product_vast_versions"}</code>, and <code>{"seller_vast_versions"}</code>, plus <code>{"format_option_ref"}</code> only when the selected option is addressable; inspected-document failures carry <code>{"mismatch_reason: document_version_mismatch"}</code>, <code>{"asset_vast_version"}</code>, <code>{"observed_document_vast_version"}</code>, and <code>{"document_role"}</code>. Only the submitted document is compared for equality with the asset declaration; wrapper and terminal documents are checked against the acceptance intersection. The deprecated <code>{"supported_versions"}</code> field remains accepted for older 3.x peers. Distinct from <code>{"VERSION_UNSUPPORTED"}</code>, which concerns AdCP protocol negotiation. Recovery: correctable (select a source VAST representation in the compatibility intersection or correct the offending document; never relabel the asset).
  </Accordion>

  <a id="error-code-vast-wrapper-depth-exceeded" />

  <Accordion title="VAST_WRAPPER_DEPTH_EXCEEDED — correctable">
    **Suggested action:** inspect error.details.reason (depth, loop, timeout); flatten the wrapper chain, reduce redirects below the format's max\_wrapper\_depth, or fix the failing hop

    Resolving a <code>{"vast"}</code> asset's wrapper chain failed: the chain exceeded the format's declared <code>{"max_wrapper_depth"}</code>, revisited a <code>{"VASTAdTagURI"}</code> already seen in the chain (a loop), or a hop did not resolve within the seller's per-hop timeout. Returned by sellers that declare <code>{"creative_specs.vast_validation: \"wrapper\""}</code>. Sellers SHOULD set <code>{"error.field"}</code> to the offending asset path and SHOULD populate <code>{"error.details.reason"}</code> with one of <code>{"depth"}</code>, <code>{"loop"}</code>, <code>{"timeout"}</code>, plus <code>{"error.details.depth"}</code> with the depth reached. Recovery: correctable (flatten the chain, reduce redirects below the format's <code>{"max_wrapper_depth"}</code>, or fix the failing hop).
  </Accordion>

  <a id="error-code-version-unsupported" />

  <Accordion title="VERSION_UNSUPPORTED — correctable">
    **Suggested action:** re-pin to a release in supported\_versions and retry, or call get\_adcp\_capabilities without a version pin to discover supported\_versions

    The declared adcp\_version (release-precision) or adcp\_major\_version (deprecated) is not supported by this seller. The error details SHOULD follow <code>{"error-details/version-unsupported.json"}</code> — <code>{"supported_versions"}</code> (release-precision strings) is authoritative for retry; <code>{"supported_majors"}</code> is deprecated. Recovery: correctable (re-pin to a release in supported\_versions and retry; or call get\_adcp\_capabilities without a version pin to discover supported\_versions).
  </Accordion>
</AccordionGroup>

## Protocols

Top-level agent capability claims. An agent claims a protocol by listing it in `supported_protocols` and must pass the protocol's baseline storyboard plus every [universal](/dist/docs/3.2.0-beta.10/building/verification/validate-your-agent#storyboard-taxonomy) storyboard.

`supported_protocols` uses snake\_case; compliance paths and specialism IDs use kebab-case. See [Naming conventions](#naming-conventions) below for the full mapping.

| `supported_protocols` value | Compliance path                     | Purpose                                                                                                                                           |
| --------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `media_buy`                 | `protocols/media-buy/`              | Campaign creation, package management, delivery optimization, conversion tracking                                                                 |
| `creative`                  | `protocols/creative/`               | Creative asset management, format discovery, rendering                                                                                            |
| `signals`                   | `protocols/signals/`                | Audience signal discovery and activation                                                                                                          |
| `governance`                | `protocols/governance/`             | Property governance, brand standards, compliance                                                                                                  |
| `brand`                     | `protocols/brand/`                  | Brand identity, rights discovery, rights acquisition *— small protocol today, growing with rights licensing work; see `brand-rights` specialism.* |
| `sponsored_intelligence`    | `protocols/sponsored-intelligence/` | AI-mediated commerce and conversational sponsored experiences                                                                                     |
| `measurement`               | Preview / no stable baseline        | Experimental 3.1 metric-catalog discovery. Agents implementing it must list `measurement.core` in `experimental_features`.                        |

<Note>
  Support for the [compliance test controller](/dist/docs/3.2.0-beta.10/building/by-layer/L3/comply-test-controller) is declared via the `capabilities.compliance_testing` block on [`get_adcp_capabilities`](/dist/docs/3.2.0-beta.10/protocol/get_adcp_capabilities), not via `supported_protocols`. Compliance testing is an RPC surface for the test harness, not a functional protocol.
</Note>

<Tip>
  An agent can claim multiple protocols — a full-stack media-buy platform might list `media_buy`, `creative`, and `signals`. The runner executes all matching baselines.
</Tip>

## Specialisms

Specific capability claims. Each specialism lives under exactly one protocol. An agent claiming a specialism must pass the specialism's storyboard in addition to the parent protocol's baseline — e.g. claiming `sales-guaranteed` requires `media_buy` in `supported_protocols`.

Specialisms carry a `status`:

* **`stable`** — fully specified storyboard. Compliance runner executes every phase; `AAO Verified` means the agent demonstrably passed.
* **`preview`** — ID and scope are reserved; the storyboard is a placeholder while the underlying protocol surface stabilizes. Agents may claim these; the runner emits a result of `{ status: "preview", passed: null, reason: "storyboard not yet defined" }` instead of a verified pass/fail. AAO badges render preview specialisms with a distinct indicator.
* **`deprecated`** — retained for backward compatibility but scheduled for removal in a future major. Runner emits `{ status: "deprecated", passed: <boolean>, reason: "..." }` — still executes the storyboard if one exists, but warns the claim should be migrated.

Status is declared per-specialism in the YAML frontmatter and surfaced in `/compliance/{version}/index.json`.

Specialisms are grouped below by parent protocol.

<Note>
  **What changed in 3.0.** `sponsored_intelligence` was promoted from a specialism to a full protocol (declare it in `supported_protocols`, not `specialisms`). `audience-sync` moved from `governance` to `media-buy` to match its tool family. `broadcast-platform` was renamed to `sales-broadcast-tv` and `social-platform` to `sales-social`. `property-governance` and `collection-governance` split into sibling `property-lists` and `collection-lists` specialisms.
</Note>

### media-buy

| Specialism                | Status     | Purpose                                                                                                                                                                                                                                                                                                  |
| ------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sales-guaranteed`        | stable     | Guaranteed media buys with human IO approval                                                                                                                                                                                                                                                             |
| `sales-non-guaranteed`    | stable     | Non-guaranteed auction-based media buys                                                                                                                                                                                                                                                                  |
| `sales-proposal-mode`     | deprecated | **Deprecated in 3.1.** Drop this claim and replace with `sales-guaranteed` + `media_buy.supports_proposals: true`. See [#3823](https://github.com/adcontextprotocol/adcp/issues/3823).                                                                                                                   |
| `sales-catalog-driven`    | stable     | Catalog-driven commerce with conversion tracking                                                                                                                                                                                                                                                         |
| `sales-broadcast-tv`      | stable     | Broadcast linear TV with guaranteed inventory and FCC cancellation rules                                                                                                                                                                                                                                 |
| `sales-dooh`              | stable     | Digital out-of-home, non-guaranteed venue and screen inventory                                                                                                                                                                                                                                           |
| `sales-social`            | stable     | Social media advertising platform with self-service flows                                                                                                                                                                                                                                                |
| `governance-aware-seller` | stable     | Seller composes with the buyer's campaign-governance agent after baseline registration — calls [`check_governance`](/dist/docs/3.2.0-beta.10/governance/campaign/tasks/check_governance) and propagates approvals, conditions, and denials unchanged. Optional claim for the full governance-check loop. |
| `audience-sync`           | stable     | Syncs buyer-provided audience segments into a platform for activation (uses [`sync_audiences`](/dist/docs/3.2.0-beta.10/media-buy/task-reference/sync_audiences), [`list_accounts`](/dist/docs/3.2.0-beta.10/accounts/tasks/list_accounts))                                                              |

<Note>
  **Coming in 3.1.** `sales-streaming-tv` (CTV / streaming), `sales-exchange` (programmatic SSP / exchange), and `sales-retail-media` (retail media network) are scheduled for 3.1. Sellers in those categories should claim `sales-guaranteed` or `sales-non-guaranteed` at 3.0 GA.
</Note>

<Note>
  `audience-sync` moved from the `governance` protocol to `media-buy` to match its tool family. If your agent claims `audience-sync` but only declares `governance` in `supported_protocols`, add `media_buy` to `supported_protocols` — the runner now expects the media-buy baseline to run alongside the audience-sync storyboard.
</Note>

### creative

| Specialism            | Status | Purpose                                              |
| --------------------- | ------ | ---------------------------------------------------- |
| `creative-ad-server`  | stable | Creative ad server with tag-based delivery           |
| `creative-generative` | stable | Generative creative agent producing assets on demand |
| `creative-template`   | stable | Creative template and transformation agent           |

### signals

| Specialism           | Status | Purpose                                                                                                                                                                 |
| -------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `signal-owned`       | stable | Owned signal agent exposing first-party segments through [`get_signals`](/dist/docs/3.2.0-beta.10/signals/tasks/get_signals); activation is not required for this claim |
| `signal-marketplace` | stable | Marketplace signal agent reselling third-party data; requires `get_signals` and [`activate_signal`](/dist/docs/3.2.0-beta.10/signals/tasks/activate_signal)             |

### governance

| Specialism                    | Status | Purpose                                                                                                                                         |
| ----------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `content-standards`           | stable | Content standards enforcement (brand safety, policy compliance)                                                                                 |
| `property-lists`              | stable | Property list governance — curated inclusion and exclusion lists for targeting and delivery compliance                                          |
| `collection-lists`            | stable | Collection list governance — curated inclusion and exclusion lists of content programs (shows, series, podcasts) for program-level brand safety |
| `governance-delivery-monitor` | stable | Campaign delivery monitoring with drift detection                                                                                               |
| `governance-spend-authority`  | stable | Conditional spend approval and human-in-the-loop governance                                                                                     |

<Note>
  **Experimental in 3.1.** Measurement metric-catalog discovery is available through the experimental `measurement` capability block and `measurement.core` experimental feature. A stable `measurement-verification` specialism and baseline storyboard are deferred until the measurement task surface is frozen.
</Note>

### brand

| Specialism     | Status | Purpose                                                          |
| -------------- | ------ | ---------------------------------------------------------------- |
| `brand-rights` | stable | Brand identity and rights licensing (talent, music, stock media) |

## Choosing a sales specialism

The `sales-*` specialisms are not mutually exclusive — a hybrid platform with both a guaranteed direct desk and an auction floor should claim both `sales-guaranteed` and `sales-non-guaranteed`. Follow the steps below to resolve your claim.

<Warning>
  **`sales-proposal-mode` is deprecated in 3.1.** Do not claim it for new agents. Existing agents that declare it must drop it entirely and replace it with `sales-guaranteed` + `media_buy.supports_proposals: true` in [`get_adcp_capabilities`](/dist/docs/3.2.0-beta.10/protocol/get_adcp_capabilities). See [#3823](https://github.com/adcontextprotocol/adcp/issues/3823).
</Warning>

<Steps>
  <Step title="Is your inventory channel-specific?">
    Four specialisms apply to specific delivery channels and have their own storyboards. If you only sell one of these channel types, claim only the matching specialism. If you also sell general display or video inventory outside these channels, continue to Step 2.

    | If you operate…                                                                                 | Claim                  |
    | ----------------------------------------------------------------------------------------------- | ---------------------- |
    | Broadcast linear TV with FCC cancellation rules                                                 | `sales-broadcast-tv`   |
    | Catalog-driven dynamic ads (product listings, restaurant menus, hotel listings, local commerce) | `sales-catalog-driven` |
    | Non-guaranteed digital out-of-home venue and screen inventory                                   | `sales-dooh`           |
    | Guaranteed-only digital out-of-home inventory                                                   | `sales-guaranteed`     |
    | Social platform with platform-managed creative                                                  | `sales-social`         |

    `sales-dooh` is the non-guaranteed DOOH profile. Guaranteed-only DOOH sellers still route `dooh` briefs through their portfolio declaration, but claim `sales-guaranteed` until a dedicated guaranteed DOOH profile exists.
  </Step>

  <Step title="What purchase model do you support?">
    | If you sell…                                  | Claim                                       |
    | --------------------------------------------- | ------------------------------------------- |
    | Guaranteed media (IO approval, fixed pricing) | `sales-guaranteed` → see Step 3             |
    | Auction / PMP non-guaranteed                  | `sales-non-guaranteed`                      |
    | Both guaranteed and non-guaranteed            | `sales-guaranteed` + `sales-non-guaranteed` |
  </Step>

  <Step title="Set media_buy.supports_proposals (sales-guaranteed only)">
    `media_buy.supports_proposals` is a boolean in the `media_buy` capabilities block of your `get_adcp_capabilities` response. It gates whether the `proposal_finalize` compliance scenario runs. It is a conformance declaration, not the buyer's per-proposal routing signal: buyers decide whether a returned proposal can be bought from `proposal_status`.

    | If you…                                                                                         | Set                                                                  |
    | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
    | Accept RFPs, generate proposals, and finalize draft proposals to committed status before create | `media_buy.supports_proposals: true`                                 |
    | Sell direct-buy guaranteed only (auction PG, retail SKU, quoted-rate — no RFP flow)             | `media_buy.supports_proposals: false` (or omit — default is `false`) |

    ```jsonc theme={null}
    // Full-service guaranteed seller — proposal lifecycle graded
    {
      "supported_protocols": ["media_buy"],
      "specialisms": ["sales-guaranteed"],
      "media_buy": {
        "supports_proposals": true
      }
    }
    ```

    ```jsonc theme={null}
    // Direct-buy guaranteed seller — proposal scenario skipped as capability_unsupported
    {
      "supported_protocols": ["media_buy"],
      "specialisms": ["sales-guaranteed"],
      "media_buy": {
        "supports_proposals": false
      }
    }
    ```
  </Step>
</Steps>

### creative

| Specialism            | Status | Purpose                                              |
| --------------------- | ------ | ---------------------------------------------------- |
| `creative-ad-server`  | stable | Creative ad server with tag-based delivery           |
| `creative-generative` | stable | Generative creative agent producing assets on demand |
| `creative-template`   | stable | Creative template and transformation agent           |

### signals

| Specialism           | Status | Purpose                                                                                                                                                                 |
| -------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `signal-owned`       | stable | Owned signal agent exposing first-party segments through [`get_signals`](/dist/docs/3.2.0-beta.10/signals/tasks/get_signals); activation is not required for this claim |
| `signal-marketplace` | stable | Marketplace signal agent reselling third-party data; requires `get_signals` and [`activate_signal`](/dist/docs/3.2.0-beta.10/signals/tasks/activate_signal)             |

### governance

| Specialism                    | Status | Purpose                                                                                                                                         |
| ----------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `content-standards`           | stable | Content standards enforcement (brand safety, policy compliance)                                                                                 |
| `property-lists`              | stable | Property list governance — curated inclusion and exclusion lists for targeting and delivery compliance                                          |
| `collection-lists`            | stable | Collection list governance — curated inclusion and exclusion lists of content programs (shows, series, podcasts) for program-level brand safety |
| `governance-delivery-monitor` | stable | Campaign delivery monitoring with drift detection                                                                                               |
| `governance-spend-authority`  | stable | Conditional spend approval and human-in-the-loop governance                                                                                     |

<Note>
  **Experimental in 3.1.** Measurement metric-catalog discovery is available through the experimental `measurement` capability block and `measurement.core` experimental feature. A stable `measurement-verification` specialism and baseline storyboard are deferred until the measurement task surface is frozen.
</Note>

### brand

| Specialism     | Status | Purpose                                                          |
| -------------- | ------ | ---------------------------------------------------------------- |
| `brand-rights` | stable | Brand identity and rights licensing (talent, music, stock media) |

### sponsored-intelligence

| Specialism               | Status  | Purpose                                                                                                                                                                                                                                               |
| ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sponsored-intelligence` | preview | Agent claim for SDKs that dispatch on specialism ID. The graded storyboard is the `sponsored-intelligence` protocol baseline; this specialism reserves the wire ID and promotes to `stable` when the SI tools graduate from `x-status: experimental`. |

## Cross-resource invariants

In addition to per-step validations, specialisms declare cross-step and cross-resource **invariants** the runner observes across the full storyboard run. These catch state inconsistencies that no single response shape would surface.

| Invariant              | Scope                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | Specialisms                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status.monotonic`     | Single-resource — rejects status transitions observed across steps that aren't on the spec lifecycle graph.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | All specialisms with a stateful resource lifecycle.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `impairment.coherence` | Cross-resource — verifies that `media_buy.impairments[]` stays in sync with referenced resources. **Forward**: every entry references a currently-offline resource. **Inverse**: any offline resource referenced by a non-terminal buy appears in `impairments[]`. **Health-iff**: on a non-terminal buy, `health == "impaired"` iff `impairments[]` is non-empty (strict iff — stale drift fails). Out of scope: all three rules relax on terminal-status buys (sellers MAY leave `impairments[]` and `health` in whatever state held at the terminal transition); materiality is schema-enforced via `package_ids: minItems: 1`. | `audience-sync`, `creative-ad-server`, `creative-template`, `creative-generative`, `sales-catalog-driven`. Driven by the [`media_buy_seller/dependency_impairment`](/compliance/latest/protocols/media-buy/scenarios/dependency_impairment.yaml) scenario (creative-track via `force_creative_status`); audience-track and catalog-track follow once the compliance test controller adds `force_audience_status` / `force_catalog_item_status`. Grades `not_applicable` on storyboards that don't observe both a resource transition and a media-buy snapshot read. |

Invariants are declared in the specialism YAML's `invariants:` array and documented inline with the rule they enforce. See [media-buy lifecycle § Compliance](/dist/docs/3.2.0-beta.10/media-buy/media-buys/lifecycle#compliance) for the full `impairment.coherence` contract.

## How to claim

Declare your protocols and specialisms in [`get_adcp_capabilities`](/dist/docs/3.2.0-beta.10/protocol/get_adcp_capabilities):

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

The storyboard runner:

1. Runs every storyboard in `/compliance/{version}/universal/`
2. For each protocol in `supported_protocols`, runs the baseline at `/compliance/{version}/protocols/{protocol}/` (snake\_case → kebab-case)
3. Runs each claimed specialism's storyboard at `/compliance/{version}/specialisms/{id}/`
4. For `preview` specialisms, emits a warning instead of a pass/fail verdict — AAO Verified badges render preview specialisms with a distinct indicator

<Warning>
  **Implement the tools AND claim the specialism.** An agent that wires all of a specialism's required tools but omits the kebab-case ID from `capabilities.specialisms[]` will be graded **"No applicable tracks found"** by the runner — `tracks_passed = 0, tracks_failed = 0, tracks_skipped = 1`. This is a silent pass at the step level and a silent fail at the track level. The fix is to add the specialism ID (e.g., `"creative-generative"`) to your `get_adcp_capabilities` response.
</Warning>

If any `stable` storyboard fails, your agent is not compliant for that claim. See [Validate Your Agent](/dist/docs/3.2.0-beta.10/building/verification/validate-your-agent) for how to run the suite locally. For a detailed walkthrough of how the runner resolves specialism manifests into graded scenarios — including how capability flags like `media_buy.supports_proposals` gate individual scenarios — see [How grading works](/dist/docs/3.2.0-beta.10/building/verification/how-grading-works).

## Naming conventions

Four casings coexist in the taxonomy. Which one applies depends on where the identifier is read:

| Casing             | Layer                                                                           | Example                                                 | Where it appears                                                                                                              |
| ------------------ | ------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `snake_case`       | Wire enums (`supported_protocols`, `delivery_type`, channel IDs, `signal_type`) | `media_buy`, `non_guaranteed`, `ctv`, `custom`          | [`get_adcp_capabilities`](/dist/docs/3.2.0-beta.10/protocol/get_adcp_capabilities) response, JSON payloads, generated schemas |
| `kebab-case`       | Specialism IDs and compliance URLs                                              | `sales-broadcast-tv`, `property-lists`, `audience-sync` | `get_adcp_capabilities.specialisms`, `/compliance/.../specialisms/{id}/` paths                                                |
| `snake_case`       | Storyboard `id:` and `category:` fields                                         | `sales_broadcast_tv`, `audience_sync`                   | Compliance YAML frontmatter, runner output, test reports                                                                      |
| Prose / hyphenated | Titles and narrative                                                            | "Streaming TV", "non-guaranteed"                        | Catalog pages, narrative copy                                                                                                 |

The kebab↔snake swap between wire specialism IDs and storyboard categories is mechanical identity — hyphens become underscores, nothing more. Variant scenarios within a specialism use `{category}/{variant}` path form.

| Specialism ID (wire)         | Channel / tool family                                                                                                                                                      | Storyboard category                                                                                  | Variant scenarios                                                                                                |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `sales-broadcast-tv`         | `channels: ['linear_tv']`                                                                                                                                                  | [`sales_broadcast_tv`](/compliance/latest/specialisms/sales-broadcast-tv/index.yaml)                 | —                                                                                                                |
| `sales-dooh`                 | `channels: ['dooh']`                                                                                                                                                       | [`sales_dooh`](/compliance/latest/specialisms/sales-dooh/index.yaml)                                 | —                                                                                                                |
| `sales-social`               | `channels: ['social']`                                                                                                                                                     | [`sales_social`](/compliance/latest/specialisms/sales-social/index.yaml)                             | —                                                                                                                |
| `audience-sync`              | [`sync_audiences`](/dist/docs/3.2.0-beta.10/media-buy/task-reference/sync_audiences) tool                                                                                  | [`audience_sync`](/compliance/latest/specialisms/audience-sync/index.yaml)                           | —                                                                                                                |
| `property-lists`             | `property_list` tools                                                                                                                                                      | [`property_lists`](/compliance/latest/specialisms/property-lists/index.yaml)                         | —                                                                                                                |
| `collection-lists`           | `collection_list` tools                                                                                                                                                    | [`collection_lists`](/compliance/latest/specialisms/collection-lists/index.yaml)                     | —                                                                                                                |
| `governance-spend-authority` | [`check_governance`](/dist/docs/3.2.0-beta.10/governance/campaign/tasks/check_governance), [`sync_plans`](/dist/docs/3.2.0-beta.10/governance/campaign/tasks/sync_plans)   | [`governance_spend_authority`](/compliance/latest/specialisms/governance-spend-authority/index.yaml) | [`governance_spend_authority/denied`](/compliance/latest/specialisms/governance-spend-authority/denied.yaml)     |
| `creative-generative`        | [`build_creative`](/dist/docs/3.2.0-beta.10/creative/task-reference/build_creative)                                                                                        | [`creative_generative`](/compliance/latest/specialisms/creative-generative/index.yaml)               | [`creative_generative/seller`](/compliance/latest/specialisms/creative-generative/generative-seller.yaml)        |
| `brand-rights`               | [`get_brand_identity`](/dist/docs/3.2.0-beta.10/brand-protocol/tasks/get_brand_identity), [`acquire_rights`](/dist/docs/3.2.0-beta.10/brand-protocol/tasks/acquire_rights) | [`brand_rights`](/compliance/latest/specialisms/brand-rights/index.yaml)                             | [`brand_rights/governance_denied`](/compliance/latest/specialisms/brand-rights/scenarios/governance_denied.yaml) |

The case split is deliberate: `supported_protocols` is a pre-existing 3.0 field already shipped to production agents, while specialism IDs are new and URL-first (each is a directory name under `/compliance/.../specialisms/{id}/`). The runner handles the mapping transparently.

### Specialism ↔ tool family mapping

The protocol an agent claims does not always match the tool family name a specialism uses:

* `audience-sync` lives under the `media-buy` protocol because `sync_audiences` is a media-buy tool.
* `property-lists` (specialism ID, kebab-case) maps to the `property_list` tool family ([`create_property_list`](/dist/docs/3.2.0-beta.10/governance/property/tasks/property_lists#create_property_list), [`validate_property_delivery`](/dist/docs/3.2.0-beta.10/governance/property/tasks/validate_property_delivery)) and storyboard category `property_lists`.
* `sales-broadcast-tv` declares `channels: ['linear_tv']` — "Broadcast TV" is the prose name; `linear_tv` is the wire value.

`/compliance/{version}/index.json` surfaces each specialism's `required_tools` so agents can discover the tool families without reading the full storyboard YAML.

### Wire enum vs prose

Wire enum values are always `snake_case` (`non_guaranteed`, `pmax_platform`, `ctv`). Prose renders the same concept with hyphens or spaces ("non-guaranteed auction inventory", "Connected TV"). When populating a payload, always use the wire form — hyphenated or spaced spellings are editorial only and will fail schema validation.

### `signal_type` values

The `signal_type` enum in signal responses has three values:

* `marketplace` — the signal agent is reselling segments published by a third-party data provider (Experian, Peer39, etc.). Buyers can verify authorization via the provider's `/.well-known/adagents.json`.
* `owned` — the signal agent exposes its own first-party segments derived from directly owned data (retailer purchase data, publisher behavioral data, telco location data).
* `custom` — the signal source builds the segment on demand from models, composites, or buyer-supplied inputs. Use this when no `adagents.json` authorization chain applies — the segment is source-native, not attributable to a standing upstream provider.

## Source of truth

The machine index is published alongside schemas:

| Path                                          | Contents                                                                                                                                                         |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/compliance/{version}/index.json`            | Enumerated protocols + specialisms + universal storyboards + per-specialism `status`                                                                             |
| `/schemas/{version}/enums/specialism.json`    | Specialism enum used by `get_adcp_capabilities.specialisms`                                                                                                      |
| `/schemas/{version}/enums/adcp-protocol.json` | Task-classification enum referenced by `tasks-list-request` and webhook payloads. Same axis as `supported_protocols` (kebab-case here, snake\_case on the wire). |

The build pipeline verifies the specialism filesystem ↔ enum parity and that every specialism's parent protocol exists in the compliance tree. Drift fails the build.

<Note>
  The catalog on this page is maintained by hand to give human context. The authoritative enumeration is always `/compliance/{version}/index.json`.
</Note>

<Tip>
  **Building an agent that wraps an upstream platform?** Storyboards in this catalog grade the AdCP wire contract; they cannot detect adapters that return shape-valid responses without integrating with the upstream. See **[Validate adapter agents with mock upstream fixtures](/dist/docs/3.2.0-beta.10/building/verification/validate-with-mock-fixtures)** for the complementary pre-staging gate.
</Tip>
