GET /api/v2/storefront/discover-agents
Queries the agenticadvertising.org registry for operator records and resolves
the publisher’s adagents.json path, including fallback discovery, for a domain.
Use it to see what the AAO registry and publisher identity documents say before
you connect or list.
Results are server-side cached for 2 minutes; pass refresh=true to bypass the
cache.
Request
curl
Parameters
| Param | In | Type | Required | Notes |
|---|---|---|---|---|
domain | query | string | Yes | Operator domain to discover agents for. Must be a valid domain (e.g. example.com) |
refresh | query | "true" | "false" | No | Set to "true" to bypass the 2-minute server-side cache and refetch |
x-aao-api-key | header | string | No | AAO session token for the calling user. When provided, the registry response is scoped to their account and includes private/draft agents. Falls back to the platform key when omitted |
Response
| Field | Type | Description |
|---|---|---|
domain | string | The domain that was queried |
operator | object | Agents registered to this operator domain |
operator.domain | string | Operator domain |
operator.member | object | null | Registry member: { slug, display_name, is_founding_member?, membership_tier?, membership_tier_label? }, or null. When null, read operator.lookup_status to tell why |
operator.lookup_status | enum | Why member is what it is: member (a record is present), not_member (looked up with full visibility, no record), scope_limited (looked up without your AAO key, so members-only records may be hidden), or lookup_failed (the registry call timed out or errored — retry with refresh) |
operator.agents[] | array | Each agent: { url, name, type } plus optional compliance, storyboards[], authorized_by[] |
publisher | object | Publisher record from the AAO registry or the adagents.json fallback |
publisher.domain | string | Publisher domain |
publisher.member | object | null | Registry member { slug, display_name }, or null. When null, read publisher.lookup_status to tell why |
publisher.lookup_status | enum | Why member is what it is: member, not_member (publisher lookups have no visibility tiers, so a null member is always definitive), or lookup_failed (registry call timed out or errored — retry with refresh) |
publisher.adagents_valid | boolean | null | Whether the adagents.json fallback validated, or null when not checked |
publisher.discovery_method | string | How the file was resolved — direct (the domain’s own /.well-known/adagents.json), authoritative_location (a centrally-hosted file covering many publishers), or ads_txt_managerdomain (the domain hosts no file of its own and delegates via its ads.txt managerdomain). Absent when no file resolved |
publisher.manager_domain | string | null | The manager domain the file was resolved from when discovery_method is ads_txt_managerdomain (e.g. cafemedia.com); null otherwise |
publisher.resolved_url | string | null | The URL the authoritative adagents.json was actually fetched from |
publisher.hosting.mode | string | The registry’s hosting state for the publisher record: self, self_invalid, aao_hosted, self_redirected, or none. This is registry metadata, not the same thing as discovery_method |
publisher.hosting.last_validated | string | null | When the registry last successfully validated the publisher-origin file. null means it has not successfully validated that origin yet |
publisher.properties[] | array | Publisher property records |
publisher.authorized_agents[] | array | Agents authorized to sell this publisher’s inventory |
How adagents.json resolves
adagents.json is the file a publisher publishes to declare which agents are
authorized to sell its inventory. Discovery does not stop at a 404 on the
publisher’s own domain — a missing file there is normal for publishers managed by
a network. Resolution follows this order:
- Direct — fetch
https://<domain>/.well-known/adagents.json. Redirects are followed only within the same registrable domain (an SSRF guard: a third-party host can’t bounce the request onto an internal address). - Authoritative-location redirect — if the direct file is a pointer (it sets
authoritative_locationand lists noauthorized_agentsof its own), follow that one hop to the centrally-hosted file it names. This is how a network or SSP can serve a singleadagents.jsonfor many publishers without each one hosting a full file. When this path is used, the response reportsdiscovery_method: "authoritative_location". - Manager domain fallback — if there is no direct file at all, read the domain’s
ads.txtand follow itsmanagerdomaindeclaration one hop, fetching that manager’sadagents.jsoninstead. This is what makes network-managed publishers resolve at all: e.g. every Raptive/CafeMedia-managed domain hosts no file of its own and delegates tocafemedia.com. When this path is used, the response reportsdiscovery_method: "ads_txt_managerdomain"and themanager_domainit resolved from. - Authorization is bound to the publisher domain. An agent is authorized only
when the resolved file grants it a property that belongs to the queried domain —
not by mere presence in
authorized_agents[]. A centrally-hosted file covering many publishers cannot make an agent authorized for a domain it wasn’t granted.
Hosting mode vs. resolved file
publisher.hosting.mode describes the AAO registry’s current publisher-record
state. It is useful for diagnosing setup, but it is not a replacement for the
resolved adagents.json verdict.
| Mode | Meaning |
|---|---|
self | The registry successfully validated a publisher-origin file at https://<domain>/.well-known/adagents.json |
self_invalid | The publisher origin returned a file, but it failed validation |
aao_hosted | AAO hosts a publisher document for this domain. The publisher still needs to make its own origin prove that document is authoritative, typically by serving an authoritative_location stub at https://<domain>/.well-known/adagents.json pointing to the AAO-hosted URL |
self_redirected | The publisher origin points to another HTTPS location through authoritative_location or an HTTP-layer redirect |
none | The registry has no publisher-hosted or AAO-hosted file configured yet |
www.<domain> is not enough by itself; https://<domain>/.well-known/adagents.json
must return the file or a crawler-accessible redirect that the resolver can follow.
Browser-only access, bot-gated responses, or HEAD/GET differences can leave the
registry in an unvalidated state even when a human can view a JSON file in a browser.
For AAO-hosted records, aao_hosted does not mean the publisher has self-hosted a
full file. It means AAO has a hosted publisher document. Origin attestation happens
when the publisher origin points at that hosted document and the registry can verify
the pointer. Until then, buyers may see AAO-hosted intent without
adagents_json origin verification.
For source families that sell publisher inventory through an agent URL, choose
the authorized agent URL from the storefront source model:
- If the seller connects an external AdCP sales agent, publishers authorize that agent’s own URL.
- If the seller connects its ad server directly to Interchange and uses
Interchange’s hosted storefront agent, publishers authorize the canonical
Interchange storefront agent URL:
https://interchange.io.
adagents.json authorization when the
module or execution path exposes a publisher-facing agent URL.
For network-managed publishers, this authorization usually belongs in the
manager’s file, with publishers delegating to that file through managerdomain or
authoritative_location. If one publisher has a direct adagents.json that points
somewhere else, that direct file can shadow the manager-domain fallback. Fix the
conflict by making the publisher’s file delegate to the same manager file, or by
removing the publisher file so its ads.txt managerdomain delegation is used.
AdCP 3.1 resolution semantics. The spec extends
adagents.json for managed
networks: a manager publishing a large agent network can use the compact
publisher_domains[] form (the authoritative file caps at 20 MB), and revocation is
expressed via a time-bound revoked_publisher_domains[] — a published, dated fact
rather than a silent removal. Interchange resolves all three discovery paths above
(direct, authoritative_location, and managerdomain fallback); the compact
publisher_domains[] / time-bound revoked_publisher_domains[] content forms are a
tracked follow-up.Errors
400 VALIDATION_ERROR—domainmissing or empty.401 UNAUTHORIZED— missing or invalid bearer token.
Related
Storefront tasks
All core storefront operations.
Resolve brand
Look up a brand profile by domain.
Storefront overview
Marketplace review and AAO signals.