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

# Publisher domains

> How storefront publisher domains are stored and synchronized to a managed sales agent

## Overview

Use `businessProfile.publisherDomains` to tell Interchange which publisher
domains your storefront is authorized to sell. This is the canonical publisher
domain set for a managed storefront.

`operatorDomain` is separate: it identifies the company or domain operating the
storefront. For network sellers, the operator domain is often not the same as
the publisher domains being sold.

<Note>
  The top-level `publisherDomain` field on `POST /storefront` and
  `PUT /storefront` is legacy metadata. Keep using `operatorDomain` for the
  storefront identity and `businessProfile.publisherDomains` for the publisher
  domains the storefront can sell.
</Note>

## Set publisher domains

Send the full current domain set on the storefront business profile:

<Note>
  The REST `PUT` below replaces the supplied business profile, so send its full
  current value. MCP clients can instead call `update_business_profile` with only
  `publisherDomains`; fields omitted from the profile state read for that call
  are preserved. Overlapping patch calls use last-writer-wins behavior.
</Note>

<CodeGroup>
  ```bash curl theme={null}
  curl -X PUT https://api.interchange.io/api/v2/storefront \
    -H "Authorization: Bearer scope3_..." \
    -H "Content-Type: application/json" \
    -d '{
      "businessProfile": {
        "agentPersonality": "Confident, concise, and commercially sharp.",
        "publisherDomains": ["mediavine.com", "cafemedia.com"]
      }
    }'
  ```
</CodeGroup>

Interchange normalizes valid domains to lowercase, deduplicates them, and saves
the sorted set. Invalid placeholder values are ignored.

## Managed sales-agent sync

For a storefront backed by an Interchange-managed sales agent,
`businessProfile.publisherDomains` is also synchronized to that managed sales
agent as the authoritative publisher-domain set.

When the set changes:

* Added domains are registered with the managed sales agent.
* Removed domains are cleared from the managed sales agent's authorization
  projection.
* Current domains are rechecked against AAO and `adagents.json` so their
  authorization status stays fresh.

## Authorization status in setup

Storefront setup lists each configured publisher domain separately. A domain can
be:

| Status                | Meaning                                                                                                    |
| --------------------- | ---------------------------------------------------------------------------------------------------------- |
| Checking              | The first AAO and `adagents.json` resolution has not completed.                                            |
| Authorized            | The resolved publisher document positively authorizes the managed sales agent.                             |
| Not authorized        | The publisher document was resolved but does not authorize the managed sales agent for the intended scope. |
| Authorization unknown | No publisher document or no conclusive authorization evidence was found.                                   |
| Check failed          | The latest publisher-document resolution failed.                                                           |

Declaring a domain (`POST /api/v2/storefront/publishers`, or a business-profile
update) kicks off its `adagents.json` resolution immediately — you do not wait
for a background sweep. The result usually lands within seconds; re-read the
publisher list to see it. A failed immediate resolve is retried by the sweep.

Re-declaring a domain you already configured re-checks it the same way,
subject to a short cooldown (currently 10 minutes) since its last completed
sync — so if you just fixed your `adagents.json`, re-declaring the domain (or
resending it in a `PUT` of the full set) gets you a fresh answer immediately
instead of waiting for the sweep. Re-declaring inside the cooldown is a no-op:
it does not reset the domain to "Checking" or trigger another fetch.

## Why a domain is not authorized

Every resolved domain also carries a machine-readable `authorizationReason`
naming the exact outcome, so you know what to fix rather than seeing a bare
"not authorized":

| `authorizationReason`      | What it means                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | What to do                                                                                                                                                                                     |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `no_file`                  | No `adagents.json` was found (a definite 404 at `https://{domain}/.well-known/adagents.json`, and no ads.txt `MANAGERDOMAIN` delegation resolved one). A transient fetch failure does not set this reason.                                                                                                                                                                                                                                                                                          | Publish an `adagents.json` on the publisher domain.                                                                                                                                            |
| `file_invalid`             | A file was retrieved but cannot be used: unparseable JSON, wrong shape, or the same agent URL listed more than once (duplicate entries are ambiguous and fail closed).                                                                                                                                                                                                                                                                                                                              | Fix the file so it parses as a JSON object with `authorized_agents[]`, and keep exactly one entry per agent URL.                                                                               |
| `agent_not_listed`         | The file is valid but your sales agent's URL is not in `authorized_agents[]`.                                                                                                                                                                                                                                                                                                                                                                                                                       | Add the agent URL to `authorized_agents[]` with a typed authorization.                                                                                                                         |
| `agent_untyped`            | The agent is listed, but its entry carries no authorization binding the platform can resolve — most often a pre-3.x file with bare `{url, authorized_for}` entries; also an unrecognized `authorization_type`, or a known type whose selector is missing or empty. Authorization is a function of the per-entry `authorization_type` + selector, so these entries fail closed.                                                                                                                      | Give the entry a resolvable typed authorization: `authorization_type` (`property_ids`, `property_tags`, `inline_properties`, or `publisher_properties`) plus its matching, non-empty selector. |
| `agent_not_property_bound` | The agent's typed entries are well-formed but grant no property authority on this publisher domain — the selector matched nothing, the resolved properties belong to other domains, or the entry is signals-only (`signal_ids`/`signal_tags`), which never conveys property authority. If the file resolved via an ads.txt `MANAGERDOMAIN` delegation, the `adagents.json` that needs the fix belongs to the manager domain, not yours — coordinate with the manager to bind your properties there. | Bind the agent to properties on this domain: fix the selector, add the domain's properties to the file, or add a property-typed entry beside a signals-only one.                               |
| `authorized`               | The resolved scope authorizes the agent for this domain.                                                                                                                                                                                                                                                                                                                                                                                                                                            | Nothing — you're live.                                                                                                                                                                         |

The reason appears on `GET /api/v2/storefront/publishers` items and on each
domain in the readiness checklist, which also summarizes the most common fix
(for example, "2 domains need an adagents.json upgrade to typed
authorizations").

Publisher-domain declaration is a go-live readiness check. Setup remains
incomplete until at least one publisher domain is configured. Product mapping
to the configured set is shown as a rollout warning while older catalogs are
backfilled. Authorization is shown separately as advisory provenance and does
not block transactions.

The status also shows the number of resolved properties when available. That
count describes what the current publisher document contains; it does not prove
that a network's document includes every site the network represents. Network
sellers should compare it with their own managed-site roster before enabling
buyer-visible coverage.

If the managed sales agent cannot accept the replacement set, Interchange keeps
the prior local publisher-domain sync state instead of deleting rows first. That
lets the update retry without losing the previous authorization projection.

<Tip>
  Send the whole set each time, not only the domain you are adding or removing.
  For example, to remove `cafemedia.com` and keep `mediavine.com`, send
  `"publisherDomains": ["mediavine.com"]`.
</Tip>

## Empty or missing values

An empty array means "clear the publisher-domain set" for the storefront:

```json theme={null}
{
  "businessProfile": {
    "publisherDomains": []
  }
}
```

Omitting `publisherDomains` means the authorized domains are unknown or have not
been captured yet. It does not authorize the storefront to sell every domain.

Setting `businessProfile` to `null` clears the business profile and clears the
publisher-domain set for managed sales-agent sync.

## Buyer visibility

Updating the publisher-domain set does not by itself change the storefront name,
operator identity, or buyer-facing seller profile. Buyers may see publisher
domain coverage on products when those products expose
`publisher_properties`; see [Publisher properties and coverage](/v2/storefront/inventory-sources/publisher-properties-coverage).

Authorization is necessary but does not by itself enable buyer disclosure. The
storefront's resolved property coverage must also be synchronized and its
coverage-disclosure rollout enabled.

## The property roster

Every declared publisher domain is resolved against the publisher's
`adagents.json`. The **property roster** is the canonical read model of what
that resolution found: each domain's declared `properties[]` (with their
identifiers, types, and tags), its `collections[]` (canonical identity
`{publisher_domain, collection_id}`), and the authorization outcome.

Fetch it with `GET /api/v2/storefront/property-roster`, the
`get_property_roster` operation, or by asking your agent to open the Property
Roster page (the `open_property_roster` tool in any MCP host).

Each publisher in the roster carries:

* `authorizationStatus` — `authorized`, `unauthorized`, or `unknown`.
* `authorizationReason` — the distinct resolution outcome behind that status:
  `no_file` (no adagents.json found), `file_invalid` (the file could not be
  read), `agent_not_listed` (the file does not list your sales agent),
  `agent_untyped` (your agent is listed in the pre-3.x format without a typed
  authorization binding), `agent_not_property_bound` (typed entries exist but
  none bind your agent to this publisher's properties), or `authorized`.
  `null` means the domain has not yet been resolved under the reason contract.
* `properties[]` and `collections[]` — persisted from the most recent
  successful resolution. Entries a newer document no longer declares are
  removed from the live roster (history is retained internally). A publisher
  that stops serving an adagents.json entirely has its declared identity
  removed from the live roster until the file returns.

The roster only reflects what publishers declare — Interchange never invents
property identity. To appear authorized, the publisher's `adagents.json` must
list your sales agent URL with a typed authorization binding
(`authorization_type` plus the matching selector, e.g. `property_ids`);
listing the URL alone is not authorization under AdCP 3.x. See
[adagents.json](/v2/storefront/inventory-sources/adagents-json) for the file
format and deployment guidance.

### Declaring properties before the publisher does

A seller can record properties conversationally — through their agent or via
`POST /api/v2/storefront/property-roster/properties` (the
`declare_roster_property` operation) — before the publisher's adagents.json
declares them. Declared entries carry `provenance: seller_declared` and are
visibly distinct from publisher-origin identity:

* A declared property needs at least a `propertyId`, an identifier, or a
  name. The roster never invents identity.
* When the publisher's adagents.json later declares the same property, the
  publisher-origin record supersedes the declared one (declaring it again
  returns `outcome: already_resolved`). Your claim is retained either way: if
  the publisher later stops declaring the property, it returns to the roster
  as your declaration instead of disappearing.
* adagents.json changes never remove seller-declared entries; remove one with
  `DELETE /api/v2/storefront/property-roster/properties/{domain}/{propertyKey}`
  (`remove_declared_roster_property`). Publisher-origin entries cannot be
  removed this way — they follow the publisher's file.
