Skip to main content

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 brand domain is often not the same as the publisher domains being sold. A third domain — the one your account is registered under — decides whether your brand domain can be verified at all. See Which domain is which if any two of them differ.
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.

Discovery publication origins

A Discovery publication origin is separate from the publisher-domain set above. It is the verified hostname where an approved, public listing (previously called the media kit or Discovery Card) is served. A registered origin serves the last verified published revision while its hostname verification remains active. When a replacement revision is published, the verified revision stays live until the replacement passes its checks. Drafts, private publications, suspended or expired registrations, and revisions that have never been verified fail closed.

Publish from the Branding & distribution Page

Seller admins manage this from the storefront’s Branding & distribution Page (the retired Settings → Discovery & distribution tab redirects here). The Page previews the canonical listing identity and reads the name, description, website, logo, and colors from the storefront’s brand.json projection. Directory and composer icons are generated from that logo when the card is published, so those values do not need to be uploaded or synchronized separately. Distribution is a two-way choice: Interchange or Public. There is no “Hidden” option — a hidden storefront can never be found, so it isn’t a distribution choice. A storefront that hasn’t published yet is shown as a state, Not listed yet, never as a third option to select. Selecting Interchange or Public publishes immediately, with no separate Publish step. An already-listed storefront can return to Not listed yet through a separate Unlist action below the two-way choice — not by selecting a “Hidden” segment, which doesn’t exist. Unlisting takes the storefront off Interchange and the public web; buyers and directories can no longer find it until it’s published again. Public also requires a public listing domain — one hostname per storefront, entered and verified at the top of the Distribution section next to the two-way choice. Choosing Public without a verified domain isn’t an error to fix elsewhere: the domain block is the walkthrough — add the CNAME shown there and select Verify. Verifying only confirms the domain is technically ready (DNS, TLS, ownership, identity); it does not select Public for you — choose Public in the two-way choice once verification succeeds. Verifying the domain also requires the storefront to already have a published Interchange listing (Publish a Discovery revision before the domain can be verified). The Interchange first-party storefront is attached to the platform-managed api.interchange.io origin automatically; it does not need a CNAME or a separate storefront hostname, and never shows the domain block. OpenAI-specific submission values, such as directory category, are entered in the OpenAI portal and are not copied into Discovery. If OpenAI asks for domain verification, the optional challenge-token control appears after the public Discovery origin is active. The public routes depend on how the origin is hosted: The first-party card uses /discovery because api.interchange.io is also the shared API origin. It does not replace the API root. Dedicated customer hostnames can serve their card at /. Every registered origin also exposes a routing proof at /.well-known/interchange-discovery-registration. Interchange periodically rechecks the hostname, HTTPS response, publication identity, and replacement revision. Public serving switches revisions only after those checks pass, and stops when active verification expires or the publication is no longer public.

OpenAI Apps domain verification

When OpenAI provides an Apps challenge token, the publication operator stores it on the active hostname registration. The exact token is then available as plain text, with caching disabled, at:
For the Interchange first-party publication, that URL is https://api.interchange.io/.well-known/openai-apps-challenge. The challenge URL is fixed by OpenAI and is not nested under /discovery. Replacing or removing a token requires explicit confirmation. A replacement invalidates the previous value immediately, and publication, replacement, and removal events are retained in an immutable audit history. The protected management view displays the saved token, its public URL, and whether the latest reachability test returned the exact value. That test does not call OpenAI or claim that OpenAI has verified the domain.
Publishing remains explicit. Saving storefront branding does not change Discovery visibility or advance its immutable public revision.

Set publisher domains

Send the full current domain set on the storefront business profile:
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.
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: The underlying adagentsStatus separates “there is no file” from “there is a file and we cannot read it”, because the fix is different: 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. Changing the effective inventory-source authorization identity also resets the current result to Checking. This happens when the storefront moves between a usable external-only identity and operator-run mode, or when an external-only storefront changes its active agents or one of their URLs. A storefront with no usable external agent URL already uses https://interchange.io, so adding or removing its first operator-run source does not reset the result. Adding another operator-run source also keeps the same identity. Interchange rechecks each configured publisher automatically.

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”: 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 — the roster’s propertyCount is the number to compare against, and it agrees with this one. 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.
businessProfile.publisherDomains is the whole set, so send all of it each time. To remove cafemedia.com and keep mediavine.com, send "publisherDomains": ["mediavine.com"]. If you only want to add or remove one domain, use the single-domain routes below instead — they do not require you to restate the rest, and restating a set you read incompletely is how domains get deleted by a request that meant to add one.

Adding or removing one domain

Two routes change exactly one domain and leave every other one alone: Prefer these over PUT /api/v2/storefront/publishers (or a business-profile update) whenever you are changing one domain. The PUT replaces the entire declared set: any domain you declared that is missing from the body is deleted, and it has no conditional-write check, so a set you assembled from an earlier read can also discard a change someone else made in between. The single-domain routes have neither problem, because they never send a set. The PUT applies as a diff, so it is safe to resend a set you already have. A domain that is in both your current set and the body keeps its row and everything resolved under it — its properties, AdCP Collections, creative formats, your own property claims, and its authorization verdict. Only the declared domains you left out are deleted, and only domains that were not there before are created (those start at pending, since nothing has resolved them yet). Only domains you declared are yours to remove, whichever route you use. DELETE returns 409 when the domain exists but its provenance is not declared — a domain we discovered or crawled for you follows its own source, and nothing is changed. The PUT behaves consistently rather than silently: it replaces your declarations only, so a discovered domain left out of the body stays on the list. Leaving one out is not a way to delete it.

Empty or missing values

An empty array means “clear the publisher-domain set” for the storefront:
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. 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 through two deliberately separate reads. AAO’s publisher lookup supplies creative format declarations, including AAO registry declarations for platforms that do not publish their own file. If that lookup is temporarily unavailable and the successfully resolved live publisher file explicitly declares formats[], those authoritative publisher-origin declarations keep the format catalog current until AAO is available again. A successful AAO lookup still owns publisher/community precedence. The live publisher-origin adagents.json read supplies authorization and continues to fail closed. The property roster is the canonical seller view of the result: each domain’s declared properties[] (with their identifiers, types, and tags), its collections[] (canonical AdCP Collection identity {publisher_domain, collection_id}), its canonical creative formats[], 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:
  • authorizationStatusauthorized, 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 mapping), agent_not_property_bound (typed entries exist but none map 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[] — Properties and AdCP 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.
  • formats[] — canonical, URL-free formatKind + params declarations from the AAO publisher lookup, or from an explicit live publisher declaration while that lookup is unavailable. Each entry retains its publisher property-id/tag scope, the live roster properties that scope matches, and provenance: publisher_adagents for publisher-origin declarations or aao_registry for an AAO registry declaration. If neither lookup provides a definitive catalog, the roster preserves the last successful catalog instead of treating the failure as an empty catalog.
  • formatCatalogSyncedAt — when the format catalog was last definitively reconciled from AAO or an authoritative live-origin fallback. This timestamp is independent of lastSyncedAt, which describes the live-origin authorization and identity check. Use the catalog timestamp to judge the freshness of preserved formats.
  • propertyCount, collectionCount, and formatCount — how many the domain actually has. For a large network these can be bigger than the corresponding arrays are long, because a single roster read is size-bounded. Read the counts, not the array lengths, when you want to know what a domain covers.
The response also carries totals for the whole storefront and a truncated object:
totals always describes the storefront, never the response. When any truncated flag is true, the response left rows out — so an absence in properties[] is not evidence a property is missing. Look the specific property up, or open the Property Roster page, rather than concluding a site is not covered.

Whether one property is authorized

Every property carries its own authorization:
Read grain before acting on status. Authorization is granted by the publisher domain’s adagents.json, and that is where we resolve it, so:
  • unauthorized is definite. The domain does not authorize your agent, so nothing under it can be sold — however many properties the file declares.
  • authorized is inherited from the domain (grain: "domain"), not proven against the specific selector mapped to your agent. Under AdCP 3.x a file can map an agent to a subset of the properties it declares.
  • unknown means no publisher-origin declaration backs this property — most often a property you declared yourself, which stays on your roster but cannot read as authorized until the publisher’s file declares it.

Storefronts where coverage does not apply

The response also carries coverageApplies. It is false for a storefront that sells through a platform account connection (Meta, Google, TikTok and the like): selling rights come from that connection, no adagents.json will ever resolve, and the authorization verdict is not something to fix. Do not read those verdicts as a problem, and do not publish a file to change them. The header totals include the number of discovered formats, and each publisher card can expand its format list. An unscoped declaration applies to every property under that publisher; a scoped declaration matches a property when either its propertyId is listed or one of its tags overlaps. Discovered publisher formats describe capacity — what the publisher says its inventory accepts. A product’s format_options[] is the closed executable set that a buyer can actually purchase from that sales agent, so it may be narrower. AAO registry provenance never authorizes a sales agent. In Property Roster, Create product opens Create a product with that publisher format already selected. Choose an Ad server, select the exact inventory to package, and choose one or more Delivery formats reported by that source. Select Review product, then Create draft product after validation succeeds. The format stays in the task instead of being sent back through chat. Review property mapping means the complete publisher roster was checked and the format did not match a current property. Mapping not shown and Check inventory mapping mean the roster view was size-bounded, so it does not contain enough properties to prove whether the format matches. Use the check action to inspect the mapping instead of treating the format as unavailable. Format IDs, sources, and the complete creative parameter object remain under Technical details. When a product uses a publisher-catalog option, copy its format_option_id, publisher_domain, format_kind, and params into the product’s format_options[]. Product validation compares that identity and canonical kind with the connected roster and warns when the option is unknown, uses a different kind, or applies to none of the product’s selected publisher properties. The product may narrow the catalog option’s parameters. These are authoring advisories: a catalog read failure does not block a product write or change the sales agent’s own validation verdict. Product validation does not yet check placement-specific format availability. 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 mapping (authorization_type plus the matching selector, e.g. property_ids); listing the URL alone is not authorization under AdCP 3.x. See 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.

Publisher onboarding

Prepare inventory source inputs

Request property-roster evidence together with avails, pricing, lifecycle ownership, and proof briefs.