Skip to main content
Every AdCP agent declares its supported_protocols and specialisms in get_adcp_capabilities. Each declaration maps to a compliance bundle at /compliance/{version}/ that the storyboard runner executes to verify the claim.
supported_protocols is not exhaustive. The accounts surface (sync_accounts, list_accounts, 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 for the full account surface.
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. 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 source taxonomy. The vocabulary remains open: agents must also handle unknown codes using the response’s recovery value.

Full descriptions

Suggested action: pass explicit account_id or a more specific natural keyNatural key resolves to multiple accounts. Recovery: correctable (pass explicit account_id or a more specific natural key).
Suggested action: choose a different operator or operator_unit identity, or retain the account’s current identity; do not retry the same desired identity unchangedThe 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).
Suggested action: replace the stale reference with error.details.current_account, refresh through list_accounts, and retry with a fresh idempotency keyAn 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).
Suggested action: verify account via list_accounts or contact sellerThe account reference could not be resolved. Recovery: terminal (verify account via list_accounts or contact seller).
Suggested action: buyer must resolve billingAccount has an outstanding balance requiring payment before new buys. Recovery: terminal (buyer must resolve billing).
Suggested action: pass account, or reference an existing resource whose owning account the service can resolveThe 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).
Suggested action: check details.setup for URL or instructionsNatural key resolved but the account needs setup before use. Recovery: correctable (check details.setup for URL or instructions).
Suggested action: contact seller to resolve suspensionAccount has been suspended. Recovery: terminal (contact seller to resolve suspension).
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 renegotiateThe requested mutation maps to an action that is not currently available on this media buy. Sellers MUST populate with (the value the request maps to), (an value: , , , , or ), and (echo of the buy’s resolved so the buyer SDK can offer recovery without a separate get_media_buys round-trip). Recovery: correctable when is (wait for or transition to an allowed status), (re-issue through the appropriate flow), or (wait until the seller can resolve the condition and advertises the action). Terminal-for-this-buy when is or — buyers select a different product or renegotiate buy terms.
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 taskThe calling buyer agent’s commercial relationship with the seller is permanently denied — the agent is blocked. Sibling to 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 : no 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).
Suggested action: surface to a human at the buyer — the agent cannot unilaterally lift a suspension; re-onboarding with the seller offline may resolveThe calling buyer agent’s commercial relationship with the seller is temporarily paused — the agent is onboarded but currently suspended. Sibling to (account-wide) and (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 payload (mirroring ‘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).
Suggested action: remove either the canonical bidding block or all legacy bidding fields from the effective packageThe 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).
Suggested action: broaden targeting or upload more audience membersAudience segment is below the minimum required size for targeting. Recovery: correctable (broaden targeting or upload more audience members).
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 presentThe 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: with a 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 / (caller credentials) and from (seller policy denies the caller). Sellers SHOULD include recovery details conforming to , especially when the caller needs to complete one of several platform connections. Legacy recovery hints such as , , or remain valid when safe to disclose. Recovery: correctable (complete or restore the required authorization, then retry).
Suggested action: do NOT auto-retry — credentials were rejected; rotate keys, refresh OAuth tokens once if applicable, otherwise escalate to a humanCredentials were presented but rejected — revoked, malformed signature, or a key no longer in the seller’s keystore. Sellers MUST return this code when an 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.
Suggested action: provide credentials via the auth header and retryNo credentials were presented. Sellers MUST return this code when no header was included in the request. Recovery: correctable (provide credentials via the auth header and retry).
Suggested action: provide credentials when missing; do NOT auto-retry rejected credentials — escalate for rotationDeprecated — use (no credentials presented) or (credentials presented and rejected). Retained as a backward-compatible alias during the 3.x deprecation window. Recovery: correctable.
Suggested action: align media-buy and package bidding scopes with the provider’s supported placement, or choose a compatible budget mode/product combinationThe 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).
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-retryThe seller’s 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 or is rejected even though the seller supports both at the capability level. Distinct from (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 instead, to prevent the distinct code from acting as an onboarding oracle. The recovery shape is deliberately minimal — MUST conform to ( plus an optional single retry value, typically ) 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 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).
Suggested action: check get_adcp_capabilities for supported_billing and resubmit with a supported value, or omit billing to accept the seller’s defaultThe seller declines the requested value either at the seller-wide capability level ( does not include the value) or at the per-account-relationship level (e.g., the seller accepts billing in general but has no direct billing relationship with the operator on this specific account). The default reject code for billing-value mismatches; SHOULD conform to ( plus optional echo for the scope) so callers can dispatch without parsing prose. Distinct from , 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 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 and MUST omit — emitting the per-agent code or the -scope hint without established identity is a cross-tenant onboarding oracle (same uniform-response shape required by the family). Recovery: correctable (check for and resubmit with a value the seller supports, or omit to accept the seller’s default).
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 reconciliationA creative-agent billing-loop operation ( 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 with the offending record(s) listed in carrying this code; the request itself is valid and silent acceptance would break buyer-side reconciliation. Distinct from (the seller declines a specific value on a media-buy account where AdCP billing is otherwise in scope) and (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 from before issuing ; agents that have not yet declared the capability remain in the probe-to-discover mode. The error is returned per-record (in the response array with pointing at or a specific record subpath), not at the envelope level. The code itself is the discriminator; no shape is defined for this code (mirroring ‘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.
Suggested action: include brand (domain plus optional brand_id) on the requestA billable operation was attempted without a brand reference. Every billable operation requires either a seller-assigned or a natural key including . Recovery: correctable (include plus optional — on the request).
Suggested action: raise max_spend, or reduce max_creatives/max_variants, to produce the remaining itemsbuild_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).
Suggested action: reduce requested amount or increase budget allocationOperation 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).
Suggested action: buyer must add funds or increase budget capAccount 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).
Suggested action: increase budget or check capabilities.media_buy.limitsBudget is below the seller’s minimum. Recovery: correctable (increase budget or check capabilities.media_buy.limits).
Suggested action: wait for the escalation to resolve; contact the plan operator if the suspension persistsCampaign governance has been suspended pending human review; the governance agent MUST reject and calls on the affected plan until the escalation is resolved. Distinct from (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).
Suggested action: remove unused catalogs, or contact the seller to raise the limitThe account has reached its maximum catalog count. Recovery: correctable (remove unused catalogs, or contact the seller to raise the limit).
Suggested action: choose a format that supports the required disclosure positions and persistence modes, or remove the disclosure requirementA 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).
Suggested action: surface to a human at the seller — the buyer cannot resolve a seller-side deployment misconfiguration and MUST NOT auto-retryThe 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 but no populated; platform declared with or but no declared; required environment variable unset on the seller process. Distinct from (buyer-fixable; the request itself is malformed), (transient; retry-with-backoff may succeed), (capability mismatch — the seller does not implement the requested specialism), (buyer-side onboarding incomplete; this code is seller-side deployment incomplete), and (governance-agent-scoped; transient). Wire placement. The deployment cannot produce a success artifact, so sellers MUST flip transport-level failure markers (HTTP 5xx, MCP , A2A ) and populate both layers per the two-layer model in . The code itself is the discriminator; no shape is defined for this code (mirroring the minimal-disclosure precedent of / ). Sellers SHOULD populate 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).
Suggested action: re-read the resource and retry with current stateConcurrent modification detected. The resource was modified by another request between read and write. Recovery: transient (re-read the resource and retry with current state).
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 comparisonA 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 (, direct plus , and deprecated ) without applying precedence. An unresolved option reference or an unprojectable legacy ID is rejected with , not this code. Once all routes resolve, sellers derive the product 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. SHOULD point at the conflicting package, and 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).
Suggested action: check creative_deadline via get_media_buys before submitting changes, or negotiate a deadline extension with the sellerCreative 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).
Suggested action: verify the asset URLs in creative_manifest are reachable without agent-side credentials, then re-submitA 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).
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_defaultA 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).
Suggested action: add the required destination URL and resubmit the creativeA 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).
Suggested action: verify creative_id via list_creatives, or sync_creatives to register itReferenced 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.
Suggested action: revise the creative according to the applicable advertising policy or validated accessibility criteriaCreative 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).
Suggested action: inspect every error.details.representation_rejections entry, then choose a compatible format option or supply a compatible representationNo 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 entry per candidate, conforming to ; 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).
Suggested action: resend the exact content previously bound to this revision_id, or mint a new revision_id for changed contentA 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).
Suggested action: resize or replace the creative with a size accepted by every selected package that may serve itThe 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).
Suggested action: correct the buyer-visible validation problem and resubmit the creativeThe 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).
Suggested action: pick a value from error.details.allowed_values (or re-fetch the format) and resubmitA submitted text-asset value is not in the format’s declared list. Distinct from (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 to the offending asset’s path within the manifest (e.g., or the field name declared by the format) and SHOULD include the format’s array in so the buyer agent can re-prompt its LLM with constrained sampling. Recovery: correctable (select a value from and resubmit).
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, , , 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 resubmitThe seller detected authentication material or caller-supplied trust material placed in request args (top-level, in , in , 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 ( 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 (no credentials presented or presented credentials rejected on the transport channel) and (authenticated caller not authorized for the action). Distinct from the receiver-side credentials carried in , 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 , A2A ) and populate both layers per the two-layer model in . The code itself is the discriminator; no shape is defined, and MUST NOT echo the offending credential value or any prefix of it (e.g., ). 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.
Suggested action: obtain a latest checkpoint, rebuild authoritative account snapshots, then drain changes after the checkpointThe 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.
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 rankingBuyer attached an evaluator agent pointer on or the agent-form — 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 . The producing agent does not call buyer-asserted endpoints outside its allowlist; this mirrors 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. MUST point at the offending path; SHOULD include a reference to the product whose the buyer should consult. Recovery: correctable (replace the agent_url with one from the seller’s published , or drop the evaluator agent pointer to fall back to seller-default ranking).
Suggested action: check URL accessibility, authentication, and that content matches the declared feed_formatPlatform 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).
Suggested action: drop the disallowed field(s) and retryA request field is not in the caller’s allowlist for this task. Sellers declaring on the account’s object MUST reject any request that sets a non-allowlisted field with this code. Distinct from (schema/business-rule violation) - the field is valid, just not writable by this caller. MUST identify the exact offending field path (e.g., ); when multiple fields are disallowed, sellers SHOULD return one error per field, or MAY enumerate them in . Recovery: correctable and agent-autonomous - agent may drop the disallowed field(s) and retry.
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-retryNon-fatal advisory raised when a product carries BOTH (v1) AND (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 (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 response is discouraged — it punishes downstream buyers for the producer bug.Surface placement (normative). Same single-surface mandate as : SDKs that detect this on consumption MUST augment the response’s array with an entry carrying , , , 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). MUST point at the offending product; SHOULD carry so buyer SDKs can flag the producer for follow-up.Multi-hop deduplication. Each hop that detects the same divergence SHOULD deduplicate by rather than re-emit; the existing entry’s identifies which earlier processor saw it first.Recovery: correctable but seller-side — buyer can’t fix divergent declarations, only flag them.
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-retryNon-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 literal). The family is known (e.g., ‘this is a video_vast’); the specific v1 named format isn’t pickable mechanically. Distinct from (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 and — SDKs MUST augment the response’s array with an entry carrying , , , pointing at the offending declaration, and SHOULD carry 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 on the v2 declaration to disambiguate (the authoritative pairing per 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.
Suggested action: advisory — emitted alongside the partial v1 emission, NOT in place of it: the v2 declaration carries 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-retryNon-fatal advisory raised when a v2 declaration carries 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 with (or if the seller self-detects on emit), , , pointing at the offending declaration, and SHOULD carry so buyer agents see which sizes were lost.SDKs MAY (non-normative) fan out automatically by catalog lookup — for each entry in lacking a corresponding , the SDK consults the AAO catalog for the per-size v1 named format (e.g., for look up ) and emits it under . 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 entries for the missing sizes.
Suggested action: refresh get_adcp_capabilities creative.supported_formats[] and retry with a capability_id whose operations contains the intended build, preview, or validate operationA 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).
Suggested action: advisory — publisher-side fix needed: a placement’s references a that does not exist in this file’s top-level . 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 or remove the reference from the placement. Do not auto-retryNon-fatal advisory raised when a placement in (or any consumer of ) carries referencing a that does NOT exist in the file’s top-level . 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 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 with , , , pointing at the offending placement (e.g., ), and SHOULD carry so the publisher can fix.Recovery: correctable but publisher-side — buyer can’t fix; publisher either declares the missing format option in or removes the reference from the placement.
Suggested action: advisory — seller-side fix needed: ask the seller to add an explicit 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 pathNon-fatal advisory raised when a legacy named format on a product cannot be projected to a canonical-formats via the resolution order in (explicit field → format_id_glob → structural match → fail-closed). The product is still valid on the legacy named-format path; only the 3.1+ projection failed. Primarily a consumer-SDK concern — the seller didn’t fail; the consumer-side SDK couldn’t project on their behalf. MUST point at the offending product (e.g., ); SHOULD carry so buyer SDKs can route remediation (suggest the seller add an explicit field, or file a registry PR).Surface placement (normative). SDKs that detect this on consumption MUST augment the response’s array with an entry carrying , , , 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 (or set ). 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 rather than re-emit. The existing entry’s identifies which earlier processor saw it first; downstream SDKs SHOULD NOT add a second entry for the same pair unless they have materially different (e.g., a different reason from a different registry version).Recovery: correctable (seller-side action — add explicit field on the legacy format file, contribute a v1-canonical-mapping registry entry, or author a 3.1+ with linking back). See canonical-formats.mdx ‘Dual emission and v2↔v1 projection’ for the full rules.
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-retryNon-fatal deprecation advisory raised when a 3.2-aware SDK encounters with a 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 with , , this code, and . Producers that self-detect their own legacy declaration MAY emit the same advisory with . Recovery is seller-side: dual-emit during the published transition window, migrate consumers, then replace the custom declaration with the promoted canonical.
Suggested action: select a governance agent matching , then retry with a fresh idempotency keyThe governance agent proposed in 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. SHOULD conform to . Distinct from , 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).
Suggested action: restructure the buy, escalate to human spending authority, or contact the governance agent for detailsA registered governance agent denied the transaction. Sellers MUST place the denial in the operation’s structured rejection arm when one exists (e.g., , or an delivery → ); otherwise in + . Buyers MUST dispatch on the response’s discriminated first and fall back to / 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 (human-readable, propagating governance findings) and (optional) and does NOT additionally emit in or . The rejection arms enforce this at the schema layer: e.g., and both declare , 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 , A2A ) — the operation completed successfully and produced a structured response.
  2. Operation response has no rejection arm (e.g., returns Success / Error / Submitted arms only). The seller populates in the payload AND on the envelope per the two-layer model in . Transport-level failure markers DO flip in this case (HTTP 4xx, MCP , A2A ) — 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. is reserved for verdicts received from a reachable governance agent; if the governance call itself failed (timeout, network, config error), use instead.
Suggested action: retry with backoff; if the agent remains unreachable, the buyer MUST contact the plan’s governance operatorA registered governance agent is unreachable. Sellers MUST place this code in + (never a structured rejection arm) and flip transport-level failure markers (HTTP 5xx, MCP , A2A ). Distinct from (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 . 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.
Suggested action: use a fresh UUID v4 for the new request, or resend the exact original payload to get the cached responseAn 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).
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 attemptThe 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.
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 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 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 — minting a new key turns a safe retry into a double-execution race. Recovery: transient (wait seconds and retry with the same ; the second attempt will either replay the now-cached response or, if still in flight, return IDEMPOTENCY_IN_FLIGHT again).
Suggested action: verify the feed content matches the declared formatCatalog 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).
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 IDA referenced in the request does not exist on the target account or product. Returned per-record in responses and at the request level for when the submitted pricing option cannot be resolved. SHOULD point at the offending record path (e.g., or ). Distinct from (the product itself is unknown) by being narrowly about a pricing option within a known product or account. Recovery: correctable (verify against the product’s from or the vendor’s discovery response, then resubmit with a valid ID).
Suggested action: check request parameters and fixRequest is malformed, missing required fields, or violates schema constraints. Recovery: correctable (check request parameters and fix).
Suggested action: check current status via get_media_buys and adjust requestOperation 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).
Suggested action: check required fields for the vendor type (vendor_cost, currency, account at minimum), fix invalid values, and resubmitA usage record in has missing or invalid fields — required fields absent, values out of range, or type mismatches. Returned per-record in the response array. SHOULD point at the offending field path (e.g., , ). Distinct from (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 , , and — fix the offending values, and resubmit).
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 compatibilityThe 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).
Suggested action: check item_issues for per-item rejection reasons and fix the offending itemsOne 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).
Suggested action: inspect error.details.macro_resolution_results and route to a resolver that supports the declared dialect, semantic, owner, and encoding depthOne 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 , conforming to ; 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).
Suggested action: verify media_buy_id; for legacy correlation use get_media_buys plus context, such as context.internal_campaign_idReferenced 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).
Suggested action: sequence single-proposal finalize calls — one finalize entry per get_products refine[] call or per refine_proposals refinements[] callReturned by sellers that cannot guarantee atomic commit across multiple proposals in a single finalize batch. Two call sites where this applies: (1) a call with multiple entries in targeting different values; (2) a call with multiple entries in targeting different 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 so buyers can distinguish ‘this seller doesn’t support multi-finalize’ from ‘the request itself is malformed’. Recovery: correctable (sequence the finalize calls one--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.
Suggested action: check the seller’s cancellation policy or contact the sellerThe 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).
Suggested action: verify package_id; for legacy package correlation use get_media_buys plus package context, such as context.buyer_refReferenced 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).
Suggested action: omit payment_terms to accept the seller’s default, retry with a different supported value, or negotiate offlineThe seller does not accept the requested value for this account. Payment terms are never silently remapped — sellers either accept or reject. Distinct from (the enum) by being narrowly about the enum on the same account. Recovery: correctable (omit to accept the seller’s default, retry with a different value the seller supports, or negotiate offline).
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 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 ; media-buy change-right and current-availability denials use . Distinct from (no credentials presented), (credentials presented but rejected), (governance agent denied), (agent’s relationship temporarily paused), and (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 — SHOULD conform to ( plus ) so callers can dispatch without parsing prose. Sellers MUST emit 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 and MUST omit — 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 uniform-response rule and . The and per-agent states are NOT carried on this code — sellers MUST emit / instead, each of which is its own discriminator. Recovery: correctable (call to mint a valid token, or contact the seller to resolve the underlying permission); when 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.
Suggested action: advisory — emitted alongside the v1 downgrade emission: SDK collapsed a pixel_tracker asset to v1 for a seller that doesn’t support pixel_tracker natively. The URL still fires; what’s lost is in (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-retryNon-fatal advisory raised when a 3.1 buyer SDK downgrades a asset to the v1 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):
  • + → no loss; emit as
  • / / / → emit with ; advisory (specific viewability variant collapses to a single v1 slot)
  • → emit with ; no meaningful loss
  • → emit with (default tracker_pixel fires on impression); advisory , (custom event timing collapses to impression timing)
  • → emit unchanged shape (url, url_type:tracker_pixel); advisory (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 with , , , pointing at the affected manifest asset path, and SHOULD carry . 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 natively.
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 / and re-prompt the seller for explicit values if precise measurement matters. Non-fatal — do not auto-retryNon-fatal advisory raised when a 3.1 buyer SDK upgrades a v1 to a 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 (which implies by default).Inference rules (normative):
  • (50% is the most common default; specific viewability variant cannot be recovered from v1 shape)
Surface: SDK MUST augment the response’s with , pointing at the upgraded asset path, and SHOULD carry . 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.
Suggested action: resolve the pinned value against the current catalog, review any replacement, and submit an intentional package targeting updateA 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).
Suggested action: verify plan_id via sync_plans, or register the plan firstReferenced 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.
Suggested action: review policy requirements in the error detailsRequest violates the seller’s content or advertising policies. Recovery: correctable (review policy requirements in the error details).
Suggested action: seller-side fix needed: remove private operational fields (, , , , 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 detailsFatal producer-side error raised when a public placement object ( in or in adagents.json) exposes seller-private operational fields such as , , , or . 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. SHOULD point at the offending placement path and SHOULD carry 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.
Suggested action: re-discover with get_products to find current inventoryThe 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).
Suggested action: remove invalid IDs and retry, or re-discover with get_productsOne 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).
Suggested action: choose a different productThe requested product is sold out or no longer available. Recovery: correctable (choose a different product).
Suggested action: call request_proposals and finalize a fresh proposal, or re-discover and finalize through legacy get_productsA 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).
Suggested action: finalize the draft through refine_proposals, or through the legacy get_products refine actionThe 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).
Suggested action: request and finalize a fresh proposal, then retryThe 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 (a known proposal whose window has passed) and (a known proposal still in ). Recovery: correctable (request a fresh proposal, finalize it, then retry accept_proposal; 3.x compatibility callers retry create_media_buy).
Suggested action: revise the provenance claim to match the verifier’s observation or replace the creative; auto-retry without correction will not passSeller invoked a governance agent from via and the verifier’s result contradicts the buyer’s provenance claim - e.g., buyer claims but the AI-detection feature returns above the seller’s confidence threshold. Distinct from the family (structural absence) by being an active refutation. SHOULD be limited to the audit-safe allowlist ; sellers MUST NOT forward arbitrary verifier extension fields, , 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), is the agent the seller actually called and SHOULD carry the buyer’s nominated 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.
Suggested action: set provenance.digital_source_type to a value from the digital-source-type enum and resubmitSeller’s is true and the submitted creative’s resolved provenance (after inheritance) has no value, or has it set to null. Distinct from (no provenance object at all) - provenance is present, just missing this specific field. Recovery: correctable (set to a value from the enum and resubmit). MUST point at the resolved provenance path that was inspected (e.g., ).
Suggested action: set provenance.disclosure.required and, when true, populate disclosure.jurisdictionsSeller’s is true and the submitted creative’s resolved provenance has no boolean, or is true with no entries. Recovery: correctable (set and, when true, populate ). MUST point at (e.g., ).
Suggested action: attach at least one embedded_provenance entry from a supported provider and resubmitSeller’s is true and the submitted creative’s resolved provenance has no array, or has it as an empty array. Used in pipelines where sidecar is stripped by intermediaries and the seller requires content-stream-resilient provenance. Recovery: correctable (attach at least one entry from a supported provider and resubmit, optionally with a pointer matching one of the seller’s ). MUST point at on the resolved manifest.
Suggested action: attach a provenance object - at minimum digital_source_type - and resubmitSeller’s is true and the submitted creative has no object on the manifest, on the creative-asset, or on any individual asset. Distinct from (generic creative-review failure) by being narrowly about provenance presence. Recovery: correctable (attach a provenance object - at minimum - and resubmit). MUST point at the path where provenance was expected (e.g., ).
Suggested action: assess the creative, set provenance.synthetic_depiction to true or false, and resubmitSeller’s is true and the submitted creative’s resolved provenance (after inheritance) has no boolean. Both and satisfy the requirement; absence means unassessed. Distinct from (no provenance object at all) and from (an independent verifier actively refuted a declared value). Recovery: correctable (assess the creative, set to true or false, and resubmit). MUST point at the resolved path. The declaration does not establish consent, legality, or verification.
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 acceptsBuyer attached a on or 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 . The seller does not call buyer-asserted endpoints outside its allowlist; this is the cross-check that closes the buyer-controlled-URL trust gap. MUST point at the offending path; SHOULD include a reference to the product whose the buyer should consult (the buyer already has this from ). Recovery: correctable (replace with one from the seller’s published , drop the entirely if the embedding is self-verifiable, or re-embed evidence using a verifier the seller accepts).
Suggested action: wait top-level error.retry_after seconds when present, then retryRequest rate exceeded. Sellers SHOULD populate top-level with the integer number of seconds to wait. Recovery: transient (wait seconds when present, then retry).
Suggested action: use a non-mutating alternative, or surface to the operator to request a scope that permits mutationThe caller’s scope is read-only; the invoked task would mutate state and was rejected. Distinct from (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.
Suggested action: verify the referenced identifier exists and is accessible to the callerGeneric 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.
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 rediscoverA 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.
Suggested action: the agent cannot broaden its own scope - surface to the operator rather than auto-retryThe authenticated caller is not authorized for the invoked task — the task is not in the caller’s for this account (discoverable via the object on sync_accounts / list_accounts responses). Distinct from (generic authz failure, often credential-shaped) by being narrowly about task-level scope. Sellers SHOULD populate pointing at where the caller can re-read its scope (strawman: ). 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.
Suggested action: retry with exponential backoffSeller service is temporarily unavailable. Retry with exponential backoff. Recovery: transient.
Suggested action: initiate a new session via si_initiate_sessionSI session ID is invalid, expired, or does not exist. Recovery: correctable (initiate a new session via si_initiate_session).
Suggested action: initiate a new session via si_initiate_sessionSI session has already been terminated and cannot accept further messages. Recovery: correctable (initiate a new session via si_initiate_session).
Suggested action: verify signal_id via get_signals, or confirm the signal is available from this agentReferenced 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.
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).
Suggested action: re-invoke the designated task (verify_brand_claim or verify_brand_claims) to obtain a freshly signed response with a current exp windowThe 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 ( / ) during step 7 of the response-signing verifier checklist. Online verifiers MUST reject expired envelopes; audit verifiers MAY verify after as historical evidence that the brand-agent signed the payload during the stated / window, but MUST NOT treat the result as current truth. Distinct from (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 window).
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 responderThe does not match the verifier’s recomputed SHA-256 hash of the canonical request-binding object for the actual request sent. Raised during step 8 of the response-signing verifier checklist. 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 . SHOULD carry (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).
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 misconfiguredThe 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. The responding brand agent derives 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 (request-binding divergence) by being narrowly about the tenant identity — 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).
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 backoffSeller 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).
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 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 (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 ONLY when the response payload is non-empty AND derived from a cache entry whose 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., ).Wire placement (normative). Transport-level success markers stay flipped to success (HTTP 200, MCP , A2A ) — the task ran successfully and produced a response, even if from cache. The advisory rides in on the payload and MUST NOT be promoted to on the envelope (envelope-level errors are reserved for the empty-payload failure case per the two-layer model in ). SHOULD point at the affected payload path (e.g., for , for ). SHOULD conform to (required, always ), (required), and optionally , (the dependency that failed), and (the underlying failure code/message).Multiple stale upstreams. When N sub-agents are stale (e.g., a registry aggregating from multiple creative agents), the seller SHOULD emit one entry per affected upstream rather than aggregating — the per-upstream shape mirrors the existing precedent set by (one advisory per downgraded asset) and lets buyer agents reason about which sub-population of the payload is stale. Each entry’s SHOULD narrow to the affected slice (e.g., 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. is the informational knob for the buyer’s own “is this stale enough to bother retrying” policy.
Suggested action: adjust the proposed terms and retry, or omit measurement_terms to accept the product’s defaultsBuyer-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).
Suggested action: target an output format the transformer prices, or have the seller add a pricing option covering itA 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.
Suggested action: check get_adcp_capabilities and remove unsupported fieldsA requested feature or field is not supported by this seller. When rejecting a request that uses a typed dimension omitted from an explicit declaration, the error details SHOULD follow names the offending dimension and 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).
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 pullsThe requested on is not in the product’s declared . Distinct from (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 when the caller is authorized to read the product’s reporting capabilities — the same set is already available via , 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 SHOULD point at . 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 may legitimately exceed (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 to fall back to cumulative date-range pulls).
Suggested action: re-issue with the entry shape the seller supports — for settings-update sellers with account-id namespaces, or for provisioning sellers; check seller documentation or capability declaration for which modes are implementedThe seller does not support the mode the entry requested. Returned per-entry in the response when (a) an entry keyed by the natural-key trio ( + + ) 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 ; or (b) an entry keyed by (AccountRef) is sent to a seller that has not implemented the settings-update mode. Distinct from (generic capability mismatch) by being narrowly about which of the two 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 (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 entries; for sellers that only provision via natural key that means the flat shape). The SHOULD point at the entry index where the unsupported shape was found.
Suggested action: review error details and fix field valuesRequest contains invalid field values or violates business rules beyond schema validation. Recovery: correctable (review error details and fix field values).
Suggested action: inspect error.details.reason (not_xml, no_vast_root, no_ad, no_media_file), fix the VAST document, and resubmitA submitted asset failed document-level validation: the inline (or the document fetched from ) is not well-formed XML, has no root element, contains no element, or an linear creative carries no . Returned by sellers that declare of or ; sellers at the default level do not inspect the VAST document and MUST NOT return this code. Distinct from (manifest-level format validation): the manifest was structurally valid, the VAST document inside it was not. Sellers SHOULD set to the offending asset path and SHOULD populate with one of , , , . Unresolved ad-server macros in URLs (, , ) are opaque tokens, not parse failures. Recovery: correctable (fix the VAST document and resubmit).
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 documentA submitted asset is version-incompatible when its exact is absent from the intersection of the selected product format option’s and the seller’s , or when an inspected document violates its applicable VAST version rule. Modern MUST conform to : acceptance failures carry , , , and , plus only when the selected option is addressable; inspected-document failures carry , , , and . Only the submitted document is compared for equality with the asset declaration; wrapper and terminal documents are checked against the acceptance intersection. The deprecated field remains accepted for older 3.x peers. Distinct from , 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).
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 hopResolving a asset’s wrapper chain failed: the chain exceeded the format’s declared , revisited a 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 . Sellers SHOULD set to the offending asset path and SHOULD populate with one of , , , plus with the depth reached. Recovery: correctable (flatten the chain, reduce redirects below the format’s , or fix the failing hop).
Suggested action: re-pin to a release in supported_versions and retry, or call get_adcp_capabilities without a version pin to discover supported_versionsThe declared adcp_version (release-precision) or adcp_major_version (deprecated) is not supported by this seller. The error details SHOULD follow (release-precision strings) is authoritative for retry; 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).

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 storyboard. supported_protocols uses snake_case; compliance paths and specialism IDs use kebab-case. See Naming conventions below for the full mapping.
Support for the compliance test controller is declared via the capabilities.compliance_testing block on get_adcp_capabilities, not via supported_protocols. Compliance testing is an RPC surface for the test harness, not a functional protocol.
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.

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

media-buy

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

creative

signals

governance

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.

brand

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.
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. See #3823.
1

Is your inventory channel-specific?

Three 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.
2

What purchase model do you support?

3

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.

creative

signals

governance

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.

brand

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. Invariants are declared in the specialism YAML’s invariants: array and documented inline with the rule they enforce. See media-buy lifecycle § Compliance for the full impairment.coherence contract.

How to claim

Declare your protocols and specialisms in get_adcp_capabilities:
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
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.
If any stable storyboard fails, your agent is not compliant for that claim. See 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.

Naming conventions

Four casings coexist in the taxonomy. Which one applies depends on where the identifier is read: 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. 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, 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: 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.
The catalog on this page is maintained by hand to give human context. The authoritative enumeration is always /compliance/{version}/index.json.
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 for the complementary pre-staging gate.