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

get_products response just hit Sam’s orchestrator. The seller — Northwind Media — quoted CTV inventory across StreamHaus, a sports network Acme Outdoor wants to be on. The CPMs look fair, the avails fit the flight, and the response arrived in under a second.
Sam has never transacted with Northwind. He has no idea whether the agent that signed this response is actually authorized to sell StreamHaus inventory, whether StreamHaus is a real publisher under a parent house he recognizes, or whether a clever attacker registered northw1nd.example last week and is about to walk away with $25,000.
He doesn’t need Northwind to convince him with a sales deck. He needs the protocol to make the chain verifiable in code — every link from the signing key on the response, through Northwind’s brand identity, to StreamHaus’s authorization, back to a parent house he can recognize. His buyer agent walks the chain automatically; Sam reads the verdict.
This walkthrough follows that chain through Sam’s eyes.
What this verifies and what it doesn’t. The chain answers who is authorized to sell. It does not answer who the legal entity behind the agent is (KYC, real operator), whether the avails reflect reality at delivery time (catalog accuracy, CPM, delivery), or whether the hosting infrastructure can be trusted (DNS, CDN, registrar). The bounded-honesty step names every limit explicitly. This is the C2PA “claim-not-certification” posture applied to inventory — the protocol carries the authorization claim and makes it verifiable, and stops there.
The chain at a glance
Three discoverable surfaces and one cryptographic check. Sam’s agent runs them in whatever order is convenient:| Surface | Source | Question it answers |
|---|---|---|
| RFC 9421 signature | Response headers | ”Did this response come from the key it claims?” |
brand.json | northwind.example/.well-known/brand.json | ”Who is Northwind, and what is it claiming to represent?” |
adagents.json | streamhaus.example/.well-known/adagents.json | ”Does the publisher authorize Northwind to sell its inventory?” |
| Mutual assertion | Both brand.json files cross-referencing | ”Do the two sides of the relationship agree?” |
adagents.json entry, not by an in-protocol claim check.
Only one of the four steps below is cryptographically grounded (the signature). The other three are integrity-checked discoveries — string-equality matches against authoritative files at well-known locations. The chain is only as strong as the publisher’s and seller’s control of their own DNS, hosting, and well-known endpoints. See Step 5 for what that implies.
Step 1: Verify the response signature

get_products response carries an RFC 9421 Signature and Signature-Input header. The keyid parameter points at a JWK in Northwind’s published JWKS. Sam’s client verifies the signature before parsing the body:
keyid produced this response, and the response has not been tampered with in transit. It does not yet tell him that keyid belongs to the legitimate Northwind. That binding comes from adagents.json in step 3.
Why signature verification comes first
Why signature verification comes first
If the signature fails, every other check is wasted work — the response cannot be trusted to even identify itself correctly. Verifying first also gives Sam a clean abort: he discards the response before any business logic touches it.
maxAge and requireCreated are not optional — without a freshness window the same signed response can be replayed indefinitely. Tune maxAge to your clock-skew budget; 300s is a common starting point.In AdCP 3.0, signing on get_products is RECOMMENDED. Mandatory signing on spend-committing operations is tracked under #2307 for 4.0. Deployments that require signing today enforce it at the platform layer.Step 2: Read Northwind’s brand.json

https://northwind.example/.well-known/brand.json. This is Northwind’s self-declaration: who it is and where its signing keys live.
- The
keyidfrom step 1 must resolve inhttps://northwind.example/.well-known/jwks.json— the JWKS Northwind’s own brand.json points at. Sam now has a binding from signature to a self-declared brand identity. - Northwind is a standalone agency — no
house_domainfield. There is no parent house claim to verify on Northwind’s side. The authorization claim that matters lives on the publisher’s side, in step 3.
Step 3: Confirm against StreamHaus’s adagents.json

https://streamhaus.example/.well-known/adagents.json — the publisher’s own declaration of who is authorized to sell its inventory:
urlmatches the MCP endpoint Northwind’sbrand.jsonnamed inagents[].url. Same agent on both sides.delegation_type: "delegated"declares the commercial relationship — Northwind is authorized to sell on StreamHaus’s behalf. The enum isdirect | delegated | ad_network; the publisher chooses which fits.signing_keys[]contains the JWK whosekidmatches the one used in step 1’s signature. This is the link Sam was missing: StreamHaus, the publisher, attests in its own file that this specific public key may sign on its behalf.
The five-state trust signal
The five-state trust signal
The brand-protocol mutual-assertion model produces a discrete signal Sam’s downstream logic can act on:
Sam’s chain resolves to
| State | Meaning | Buyer action |
|---|---|---|
inline | The seller is the brand owner — no delegation involved | Proceed; nothing to delegate |
mutual_assertion | Both sides published matching declarations | Proceed |
one_sided_brand | The seller’s brand.json claims a publisher; the publisher hasn’t reciprocated | Do not treat as authorization. Any domain can claim any publisher unilaterally. |
one_sided_house | The publisher’s adagents.json names the seller; the seller’s brand.json doesn’t acknowledge | Hold for human review |
standalone | Neither side publishes — bearer-token trust only | Out-of-band authorization or refuse |
mutual_assertion — the strongest state short of inline. Only inline and mutual_assertion close the chain.Step 4: Walk the parent house

house_domain ↔ Sportshaus Holdings’ brand_refs[].domain. Both sides agree.
Two distinct concepts ride along this step, and the doc is careful not to conflate them:
- The
keller_typeon the child (endorsed) describes the brand-architecture relationship — how the sub-brand is positioned beside the parent. It is Keller-architecture metadata, not a commercial authorization. - The commercial relationship that lets Northwind sell is
delegation_type: "delegated"from step 3, which lives on the publisher (StreamHaus), not on the parent house.
brand.json → StreamHaus’s adagents.json → StreamHaus’s and Sportshaus Holdings’ mutual brand.json declarations. Four discoverable surfaces, one cryptographic anchor, zero phone calls for the authorization question.
Step 5: Know what the chain does not prove

| The chain proves | The chain does not prove |
|---|---|
Northwind is authorized to sell StreamHaus inventory under a delegated relationship | A real human at Northwind operates this agent and answers for it |
| The signing key is named by both the seller and the publisher | The operator behind that key has been KYC’d by anyone Sam trusts |
| StreamHaus declares Sportshaus Holdings as its parent, and the parent reciprocates | The legal counterparty matches who Sam thinks he’s transacting with |
| The response was not tampered with in transit | The avails in the response will be available on the flight start date, or the CPM quoted will hold |
| Northwind’s domain controls the signing key today | The key cannot be rotated to an attacker tomorrow — first-encounter trust is TOFU until key transparency lands in 4.0 |
northwind.example, its DNS, TLS, and CDN. A registrar takeover, a CDN compromise, or a mis-issued TLS certificate substitutes the entire chain — the attacker serves attacker-controlled brand.json, adagents.json, and JWKS over a valid-looking pipeline. There is no public key-transparency log in 3.x; first-encounter trust is trust-on-first-use, and revocation is detectable only by re-fetching. A buyer client that has previously transacted with Northwind pins the seen kids and warns on rotation; a buyer client on first encounter does not have that signal. See #3925.
The delivery-time gap. Catalog accuracy is not protocol-attested. Publishers do not sign individual product entries, and per-product attestation does not match how inventory operates in production — forecasts drift, prices move, supply is dynamic. A misbehaving authorized seller is remediated by the publisher revoking the adagents.json entry, not by an in-protocol claim check. Delivery-time truth lives in measurement and billing reconciliation.
This is the C2PA “claim-not-certification” posture. The protocol carries the authorization claim and makes it cryptographically verifiable. It does not — and at the protocol layer should not — replace the human-layer, hosting-layer, or delivery-layer checks a buyer would do for any meaningful new counterparty.
What Sam does next
Sam’s client logs the verification result with theget_products response — including the captured brand.json, adagents.json, and JWKS bytes at decision time, not just pointers to live files. Months from now, an auditor can re-verify the signature against those captured artifacts and reproduce Sam’s decision exactly. Re-fetching the live .well-known/ files is not sufficient — they are mutable, and a single key rotation or domain transfer would invalidate a naive replay.
The verification result and the five-state trust signal travel with the candidate plan into Sam’s governance flow, where Jordan’s governance agent applies Acme’s policy checks before any spend is committed.
Where to go from here
- brand.json reference — full schema for self-declarations, parent-house portfolios, and Keller architecture metadata
- adagents.json reference — publisher-side authorization, the
authorization_typediscriminator, and thesigning_keys[]JWK shape - verify_brand_claim — Tier-2 implementer guide for delegating verification to a brand agent
- Security model — three-party governance and trust posture
- Request signing — RFC 9421 details, key rotation, transparency-log roadmap
- Trust & Security — CISO-facing surface map; this walkthrough is the buyer-facing companion
- AAO Verified — continuous behavioral conformance attestation, layered on top of the identity chain above