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

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.

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, 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. 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 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[] — 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. 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 an AAO lookup fails, the roster preserves the last successful catalog instead of treating the failure as an empty catalog.
  • formatCatalogSyncedAt — when AAO last returned a definitive format catalog for this publisher. 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.