Status: Request for Comments Last Updated: April 19, 2026Documentation Index
Fetch the complete documentation index at: https://docs.adcontextprotocol.org/llms.txt
Use this file to discover all available pages before exploring further.
Two words, not three
AdCP conformance has two load-bearing terms. A third (one you’ll hear in the wild) is a trap.- Conformant — the agent meets the normative rules. Defined by the storyboards this document indexes.
- Verified — AAO has tested the agent recently and issued a signed attestation. Gated on active membership and a live heartbeat. The AAO Verified badge carries one of two qualifiers: (Spec) for storyboard-conformance against a test deployment or dev endpoint, (Sandbox) for storyboard-conformance against the seller’s real production endpoint under
account.sandbox: trueflagging. An agent can earn either or both. - “Compliant” — self-attested, unverified, no external check. Don’t claim it; don’t design for it. This document uses conformant and verified exclusively.
- Conformance is a property of the agent’s wire behavior.
- Verification is a time-bounded third-party attestation. (Spec) attests wire-format conformance against any registered endpoint; (Sandbox) attests the same storyboard suite passes against the seller’s real production endpoint under sandbox-flagged traffic. Same storyboards, different attestation surface.
- The two axes are independent: a seller without a separate test deployment can earn (Sandbox) directly on production; a test agent that can never serve real impressions earns (Spec) as a complete claim.
Storyboard conformance vs. AAO Verified
This page indexes storyboard conformance — the property an agent’s wire behavior has when it matches the spec, verified by storyboards running against seeded test data. Storyboard passing earns the AAO Verified (Spec) or AAO Verified (Sandbox) qualifier (or both) on an agent’s badge, depending on where the runner targeted. A second axis — AAO Verified (Sandbox) — verifies the seller’s real production endpoint correctly handles the full storyboard suite underaccount.sandbox: true flagging. (Sandbox) is the stronger claim: a seller can pass (Spec) on a test deployment while their production stack has a broken sandbox gate (real-world side effects under flagged traffic, missing account-mode verification, etc.) — (Sandbox) closes that gap.
The two qualifiers share one brand mark — AAO Verified — and an agent can earn either or both. (Spec) and (Sandbox) are independent: each independently demonstrates conformance through different evidence. (Spec) attests wire-format conformance against any registered endpoint; (Sandbox) attests the production code path correctly tolerates sandbox-flagged traffic. See AAO Verified for the qualifier model and the Sandbox framing verdict; the rest of this page indexes the storyboards that back both qualifiers.
Test surfaces and the storyboard loop
Every seller exposes a test surface — the mechanism that lets a storyboard runner exercise the seller’s tools deterministically without triggering real-world side effects. The test surface is what (Spec) is graded against. How a seller stands up that surface depends on where their state-of-record lives; the implementation differs, the goal does not:| Where state-of-record lives | How the test loop closes |
|---|---|
| Local DB only (typically SSPs, creative agents) | The storyboard runner writes fixtures via comply_test_controller.seed_*; the seller’s read handlers consume the same store. The seed → read loop closes naturally. |
| Upstream system the seller does not control (DSPs proxying to platforms, retail-media networks reading retailer catalogs, signals brokers) | Seeded writes are dead to the read handler. The TypeScript SDK ships a TestControllerBridge that runs the real adapter call first (so a broken upstream call still fails the gate), then merges seeded fixtures into the response. |
| Mixed (some tools local, some upstream) | Both, per tool. |
(Spec) — both prove the seller’s wire format matches the storyboards. The bridge is one implementation of the test-surface pattern, not a separate seller category. A state-local seller without wired seeds and an upstream-proxy seller without a wired bridge are in the same position: storyboards cannot run end-to-end against them. Neither category is what (Sandbox) attests; (Sandbox) is the separate axis covering whether the seller’s production stack honors account.sandbox: true without real-world side effects.
Distinguishing fixture-merged from upstream-derived responses
When a response passes through the SDK’sTestControllerBridge, the SDK stamps a _bridge: { callback, tool, merged_count } marker on the response. Marker presence on a step means the response content was merged from a seeded fixture after the seller’s handler returned; marker absence means the response came from the seller’s adapter end-to-end (or from a local DB the runner seeded directly). The marker is advisory metadata for runners and downstream leaderboards — it is not part of the wire contract. Sellers MUST NOT emit it, and conformance checks ignore it. The leading underscore marks the field as SDK/runner-stamped metadata reserved for testing tooling; future fields with the same prefix follow the same rule.
Marker design: adcp-client#1775. Shipped: adcp-client#1786. Leaderboard policy that consumes the marker: adcp-client#1782.
Three signals — don’t conflate them
Adopters often read these three controls as the same thing. They answer different questions:| Signal | Question it answers |
|---|---|
Test controller availability (comply_test_controller in tools/list) | “Has the seller exposed deterministic-mode forces?” |
Sandbox flag (account.sandbox on requests) | “Is the targeted account a sandbox account, with no real-world side effects?” |
Bridge participation (_bridge marker on a response) | “Did this response come from the adapter’s upstream call, or from a fixture the SDK merged in?” |
(Spec) and (Sandbox) verification qualifiers, which describe what a storyboard pass attests over time. A storyboard pass can carry any combination of the three signals.
Storyboards are the truth
Rather than restate every MUST in prose — which would inevitably drift from the executable suite — the storyboards ARE the conformance specification. This document is a navigational index to them, grouped by the declaration that obligates the storyboard to run. Every normative rule in the suite has exactly one home: the storyboard YAML at/compliance/latest/. Changes to what “conformant” means happen there, in a versioned release, tested against real agents. If a rule isn’t in a storyboard, it’s not part of conformance.
This is deliberate. A separate prose spec that restates storyboard rules creates two sources of truth. Two sources of truth drift. We pick one: the suite.
The
@adcp/sdk package also ships TypeScript files under testing/scenarios/ that pre-date storyboard-driven comply(). They are not the conformance spec — see Storyboards vs. scenarios for which is which.Conformance is layered
Every agent satisfies the universal layer. Eachsupported_protocols claim adds a protocol baseline. Each specialisms claim adds a specialism baseline.
| Layer | Obligation | Path |
|---|---|---|
| Universal | Every AdCP agent | /compliance/latest/universal/ |
| Protocol | Agent claiming a supported_protocols value | /compliance/latest/protocols/{protocol}/ |
| Specialism | Agent claiming a specialisms value | /compliance/latest/specialisms/{id}/ |
Universal conformance
Every agent MUST pass every storyboard below.| Storyboard | What it verifies |
|---|---|
capability_discovery | get_adcp_capabilities shape, protocol/specialism declarations, version advertising |
comply_controller_mode_gate | Sandbox/live isolation for sellers that expose comply_test_controller on a shared endpoint — live-mode principals must be refused before scenario dispatch |
schema_validation | Request and response schema conformance, ISO 8601 timestamps, temporal invariants |
schema_validation_signals | Response schema compliance for signals — required fields on every signal; gated on get_signals |
version_negotiation | Release-precision adcp.supported_versions advertisement and response-envelope adcp_version echo; advisory in 3.1, promoted in later cuts |
v3_envelope_integrity | v3 protocol envelopes MUST NOT carry the v2 legacy task_status or response_status fields — status is the single canonical lifecycle field in v3 |
error_compliance | Structured error shape, published error codes, transport binding, no existence leaks across tenants |
error_compliance_signals | Error handling for signals protocol — nonexistent signal IDs, missing fields, VERSION_UNSUPPORTED, transport binding; gated on get_signals + activate_signal |
stale_response_advisory | STALE_RESPONSE wire placement — advisory rides in errors[] on a populated success response with transport success preserved; stale-cache forcing steps gated on comply_test_controller with force_upstream_unavailable |
idempotency | idempotency_key scoping, replay semantics, IDEMPOTENCY_CONFLICT, replayed: true, declared TTL |
read_tool_idempotency | Read-only task wrappers accept the 3.1 every-request idempotency_key envelope without strict request-wrapper rejection; includes the 3.1 omitted-key grace probe |
canonical_format_validate_input | Canonical-format validate_input result semantics: structural pass/fail across required slots and unvalidatable_nondeterministic for seeded product declarations. Gated on agents that advertise validate_input; the seeded-product branch also requires comply_test_controller seeding support. |
security_baseline | Unauth rejection, static-credential enforcement (Bearer API key or HTTP Basic), OAuth discovery + RFC 9728 audience binding |
webhook_emission | Outbound webhook conformance — stable idempotency_key across retries, RFC 9421 webhook signing (or opt-in HMAC fallback) on every delivery. Runs for any agent accepting push_notification_config. |
notification_config_event_scope | sync_accounts.accounts[].notification_configs[] semantic validation — account-level subscribers reject media-buy-anchored notification types even though those values are valid in the shared enum |
notification_config_lifecycle | Account-level notification_configs[] lifecycle on sync_accounts: paused registration, durable list_accounts echo, subscriber-keyed replacement, and clear-all semantics |
notification_config_rejections | Semantic notification_configs[] request rejection path for duplicate subscriber_id values |
wholesale_feed_products | Product wholesale feed versioning: bootstrap responses carry wholesale_feed_version/cache_scope, and matching if_wholesale_feed_version probes return unchanged without product rows |
wholesale_feed_signals | Signals wholesale feed versioning: bootstrap responses carry wholesale_feed_version/cache_scope, and matching if_wholesale_feed_version probes return unchanged without signal rows |
wholesale_feed_product_webhooks | Account-level notification_configs[] registration for agents that advertise product wholesale feed webhook events |
wholesale_feed_signal_webhooks | Account-level notification_configs[] registration for agents that advertise signal wholesale feed webhook events |
wholesale_feed_bulk_webhooks | Account-level notification_configs[] registration for agents that advertise wholesale_feed.bulk_change |
pagination_integrity | cursor ↔ has_more invariant on paginated list_creatives responses, walked from a continuation page through to a terminal page |
get_signals_pagination_integrity | cursor ↔ has_more invariant on paginated get_signals responses under a broad query, with first-page non-terminal assertion against any non-trivial signal set |
pagination_integrity_list_accounts | Continuation-side pagination integrity on list_accounts responses; storyboard bootstraps three sandbox accounts via sync_accounts, requires has_more=true with a usable cursor on the first page, and follows that cursor once |
pagination_integrity_creative_formats | cursor ↔ has_more invariant on paginated list_creative_formats responses; storyboard seeds two creative formats via seed_creative_format and walks from a continuation page to a terminal page |
get_media_buys_pagination_integrity | cursor ↔ has_more invariant on paginated get_media_buys responses; storyboard seeds three media buys via seed_media_buy and walks from a continuation page to a terminal page |
pagination_integrity_content_standards | cursor ↔ has_more invariant on paginated list_content_standards responses; storyboard bootstraps three content standards configurations via create_content_standards and walks from a continuation page to a terminal page |
pagination_integrity_collection_lists | cursor ↔ has_more invariant on paginated list_collection_lists responses; storyboard bootstraps three collection lists via create_collection_list and walks from a continuation page to a terminal page |
pagination_integrity_property_lists | cursor ↔ has_more invariant on paginated list_property_lists responses; storyboard bootstraps three property lists via create_property_list and walks from a continuation page to a terminal page |
deterministic_testing | comply_test_controller state machine — skipped if capabilities.compliance_testing.supported: false |
signed_requests | RFC 9421 transport-layer request-signing verification — skipped if request_signing.supported: false. |
billing_gate_dispatch | Two-gate dispatch on sync_accounts.billing rejection: seller-wide capability gate (BILLING_NOT_SUPPORTED with error.details.scope) vs per-buyer-agent commercial-relationship gate (BILLING_NOT_PERMITTED_FOR_AGENT with the clamped rejected_billing + optional suggested_billing shape). Capability phase skipped when the seller supports all three billing values; per-agent phases skipped when the test kit does not declare commercial_relationship: passthrough_only. |
capabilities.compliance_testing.supported: true MUST implement the full test controller; a partial controller is non-conformant, so declare false rather than ship one.
Agents that declare request_signing.supported: true MUST implement the full RFC 9421 verifier per the request-signing profile; a partial verifier is non-conformant, so declare false rather than ship one.
Protocol conformance
Asupported_protocols claim obligates the protocol’s baseline storyboard.
supported_protocols | Storyboard |
|---|---|
media_buy | media_buy_seller + media_buy_state_machine |
creative | creative_lifecycle |
signals | signals_baseline |
governance | media_buy_governance_escalation |
brand | brand_baseline |
sponsored_intelligence | si_baseline |
Specialism conformance
Aspecialisms claim obligates the specialism’s storyboard in addition to its parent protocol baseline. The catalog lives at /compliance/latest/index.json; the human-readable index is the Compliance Catalog.
Specialisms carry a status — stable (verified pass/fail), preview (storyboard not yet defined; runner emits passed: null), deprecated (scheduled for removal). Agents MAY claim preview specialisms, but preview claims do not yield a pass/fail verdict.
Outside the wire
Some requirements can’t be verified by a storyboard because they’re operator-level, not wire-level. They remain part of running a conformant agent, but the suite can’t attest to them. Operators MUST self-assess against these; third-party frameworks (SOC 2, ISO 27001) are the usual attestation path.- Secret storage — credentials SHOULD live in a KMS or equivalent. The wire shows only whether auth succeeds, not where the key was stored.
- Credential rotation and revocation — the operator MUST have a documented path to revoke a compromised credential in under an hour. The wire can’t observe the runbook.
- Personnel and physical security — who can touch production, break-glass custody, employee offboarding. Entirely outside the protocol.
- Governance agent due diligence — when the operator relies on a third-party governance agent, the buyer SHOULD treat it as a processor with multi-customer blast radius and assess its posture. The storyboards verify correct JWS handling by the seller but cannot vouch for the governance agent itself.
- LLM subprocessor posture — if the agent uses an LLM provider, the DPA with that provider governs whether prompts, brand assets, or creative metadata may be retained. The protocol can’t see upstream DPA terms.
- Incident response — AdCP emits the signals worth watching (
IDEMPOTENCY_CONFLICTspikes, failed governance verifications, SSRF rejections); detection, alert routing, and response are operator concerns. - Data residency configuration — whether and how EU / UK data is kept in-region is typically declared in the agent’s capabilities or contract; the wire records the declaration, not the underlying infrastructure.
Conformance vs external assurance
Conformance is wire-level correctness. SOC 2, ISO 27001, and NIST CSF are operational assurance. They answer different questions and neither substitutes for the other.| External control area | Storyboard evidence | Gap to external assurance |
|---|---|---|
| Access control (SOC 2 CC6, ISO 27001 A.5.15) | security_baseline (identity) + isolation checks in protocol storyboards | Personnel access reviews, least-privilege admin, offboarding |
| Change management (SOC 2 CC8) | idempotency proves duplicate state changes are prevented on the wire | Deployment approvals, release gates, rollback procedures |
| System monitoring (SOC 2 CC7, ISO 27001 A.8.16) | Error taxonomy produces a monitorable surface | Detection engineering, alert routing, on-call runbooks |
| Cryptography (ISO 27001 A.8.24) | TLS, RFC 9421 signing, JWS governance tokens | KMS selection, rotation cadence, cert lifecycle |
| Audit logging (SOC 2 CC7) | Governance storyboards verify signed-record issuance | Log retention, legal hold, integrity monitoring |
| Data handling (SOC 2 Privacy, GDPR, ISO 27701) | TMP two-call separation, audience hashing, signal access control | Data subject rights, DPA management, cross-border transfer |
| Vendor and subprocessor risk (SOC 2 CC9) | adagents.json / brand.json discovery, JWKS publication | Third-party risk assessment, LLM provider review |
| Incident response (SOC 2 CC7, NIST CSF RS) | Signals observable; response not mandated | Runbooks, tabletop exercises, breach notification |
| Business continuity (ISO 27001 A.5.30) | Cross-instance state storyboard checks | RPO/RTO targets, DR testing |
- Storyboard pass evidence MAY support specific external control objectives. It is not a substitute for an audit.
- External certification does not imply AdCP conformance. SOC 2 Type II says nothing about whether
create_media_buyresponses validate.
How to claim conformance
- Declare
supported_protocolsandspecialismsinget_adcp_capabilities. - Pass every storyboard the declaration obligates — universal + protocol baselines + specialism baselines — at a specific AdCP major version.
- Keep declaration and behavior in sync. An undeclared capability the suite happens to test is separate from a declared capability that fails. Both are non-conformant.
What this document does not do
- Define individual MUSTs. The storyboards do. If a rule isn’t in a storyboard, it isn’t part of conformance.
- Grant or revoke certification. The AgenticAdvertising.org certification program runs on top of this; conformance is necessary but not sufficient.
- Publish reference test vectors beyond those already in the suite. The Reference Test Vectors index catalogs the vector sets that ship today; broader task-level corpus lands incrementally between 3.0 GA and 3.1, scoped in #2383.
When a storyboard fails
When a failure surfaces a disagreement between the spec, the mock, and an SDK, the section below gives the triage order. For symptom-to-cause lookup, see the links at the end of this section.Mock-server authority and failure triage
Theadcp mock-server is the reference wire implementation for stable surfaces. Use this triage order when a storyboard failure implicates the mock or an SDK:
Triage order: spec → mock → SDK. The storyboards (and the schemas they reference) are canonical. The mock interprets the storyboards. The SDK consumes the protocol via the mock.
| Condition | Default verdict | Next step |
|---|---|---|
| SDK wire shape differs from the mock’s | SDK is wrong | File a bug against the SDK |
| SDK wire shape matches the mock’s, but a storyboard still fails | Mock is wrong | File an issue against adcontextprotocol/adcp to fix the mock |
| Storyboard assertion conflicts with an otherwise-passing wire shape | Storyboard is wrong | File an issue against adcontextprotocol/adcp to fix the storyboard |
| Spec text (storyboard prose or schema) explicitly contradicts the mock | Spec wins; mock is the bug | File an issue against adcontextprotocol/adcp to fix the mock |
- Storyboard troubleshooting — Error pattern → root cause → fix for the most common storyboard failures
- Known spec ambiguities — Open spec gaps with workarounds and issue links; entries are removed as underlying issues close
Further reading
- AAO Verified — Continuous-observability verification of the seller’s live ad-server integration
- Compliance Catalog — Full taxonomy of protocols and specialisms with storyboard IDs
- Validate Your Agent — How to run the suite
- Security Model — Strategic framing for the five defense layers that the security storyboards enforce
- Security (implementation reference) — Normative rules cited by the storyboards
- Versioning — Major-version support windows
- Known Limitations — Visible edges of the specification