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

# Discover agents

> Find the operator and publisher agents authorized for a domain

`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

```bash curl theme={null}
curl "https://api.interchange.io/api/v2/storefront/discover-agents?domain=acme-media.example.com" \
  -H "Authorization: Bearer $SCOPE3_API_KEY"
```

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

```json theme={null}
{
  "domain": "acme-media.example.com",
  "operator": {
    "domain": "acme-media.example.com",
    "member": {
      "slug": "acme-media",
      "display_name": "Acme Media"
    },
    "lookup_status": "member",
    "agents": [
      {
        "url": "https://agent.acme-media.example.com/mcp",
        "name": "Acme Media Sales Agent",
        "type": "sales",
        "compliance": {},
        "storyboards": [],
        "authorized_by": []
      }
    ]
  },
  "publisher": {
    "domain": "acme-media.example.com",
    "member": {
      "slug": "acme-media",
      "display_name": "Acme Media"
    },
    "lookup_status": "member",
    "adagents_valid": true,
    "discovery_method": "direct",
    "manager_domain": null,
    "resolved_url": "https://acme-media.example.com/.well-known/adagents.json",
    "hosting": {
      "mode": "self",
      "last_validated": "2026-06-25T14:48:42.000Z"
    },
    "properties": [],
    "authorized_agents": []
  }
}
```

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

1. **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).
2. **Authoritative-location redirect** — if the direct file is a *pointer* (it sets
   `authoritative_location` and lists no `authorized_agents` of its own), follow that
   one hop to the centrally-hosted file it names. This is how a network or SSP can
   serve a single `adagents.json` for many publishers without each one hosting a full
   file. When this path is used, the response reports
   `discovery_method: "authoritative_location"`.
3. **Manager domain fallback** — if there is no direct file at all, read the domain's
   `ads.txt` and follow its `managerdomain` declaration one hop, fetching that
   manager's `adagents.json` instead. 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 to `cafemedia.com`. When this path is used, the response reports
   `discovery_method: "ads_txt_managerdomain"` and the `manager_domain` it resolved from.
4. **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                                                                                                                                                                                                      |

When a publisher moves from AAO-hosted to self-hosted, the registry only converges
after the queried domain's well-known URL is crawler-accessible. A file on a sibling
host such as `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`.

Linked storefront inventory uses the upstream storefront's own authorization
model. Modular sources only need publisher `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.

<Note>
  **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.
</Note>

## Errors

* `400 VALIDATION_ERROR` — `domain` missing or empty.
* `401 UNAUTHORIZED` — missing or invalid bearer token.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Storefront tasks" href="/v2/storefront/tasks" icon="list-check">
    All core storefront operations.
  </Card>

  <Card title="Resolve brand" href="/v2/storefront/tasks/resolve-brand" icon="building">
    Look up a brand profile by domain.
  </Card>

  <Card title="Storefront overview" href="/v2/storefront/overview" icon="store">
    Marketplace review and AAO signals.
  </Card>
</CardGroup>
