Skip to main content
An account administrator can set the commercial operator domain and operating-unit code, inspect an advertiser’s linked brand, and follow supported verification work through v3. The responses include the details in text; an MCP App or Settings page is not required for these steps. Commercial identity, public branding and domain proof are separate. Saving a domain or finding a public brand.json does not grant account access, prove domain ownership or authorise an agent to act for that brand. Organisation names, login domains, users and roles are outside this setup flow.

Select the confirmed identity contract

For this workflow, send identityContract: "confirmed-v1" on every operator identity save or advertiser brand correction. Keep it on the preview, confirmation and retry calls. Replacing an existing identity in this contract requires a preview and the person’s explicit confirmation; omitting the token returns CONFLICT without saving. This contract coexists with earlier v3 saves on the same tools. Calls using only the earlier fields retain their existing behaviour, including one-call Buyer operator and advertiser brand updates and the Seller’s confirmOperatorDomainProfileReset check. They do not acquire a new preview requirement. New setup integrations should select confirmed-v1 explicitly. Supplying preview (including false), confirmationToken, or an advertiser update’s publicBrand also opts into the confirmed contract. An unsupported identityContract value is rejected; it does not fall back to an earlier save.

Find the account and its current identity

Call tools/list, then get_status with no accountId. Name the account ID it returns as accountId on every call, and read status for that account. A principal with several accounts must name the Buyer or Seller Account it intends to configure. An Organisation-only account provides orientation and support asks; it does not expose a separate identity editor. For a Buyer, operatorDomainSource: "legacy_customer_domain" identifies a fallback from the account record. It is not a confirmation of the commercial identity. domainProof reports the separately recorded verification and its source. organization and aao describe the evidence used by readiness; inspect them alongside locked. Every Buyer get_status read looks the company up in the AgenticAdvertising.org (AAO) registry, the same lookup the web app makes, and reports what it finds in aao. The registry match never decides whether the company is verified: that always comes from Apostra’s own domain evidence. The lookup has a short deadline. When the registry is slow or fails, aao.status is unavailable and the read still answers. blockers lists exactly the setup checks that block buying and are not yet complete, in checklist order: operator_identity, terms, account_standing, payment_terms and billing_details. billing_details blocks while the billing organization lacks a payer name, street address or country and the buyer buys from a consolidated-billing seller. state and nextActions read the same checks, so a blocker never appears in one and not the other.

Read the whole setup checklist and every seller

A Buyer get_status call can return the full checklist and one row per seller. Send include: ["setup"]. Only a Buyer account accepts it: any other account kind is refused with VALIDATION_ERROR naming include. A seller’s status is one of ready, seller_unavailable, needs_connection, needs_account_selection, needs_advertiser_mapping, needs_commercial_setup or platform_blocked. Every action is a tool call, { "tool": "...", "arguments": { ... } }, or null when there is nothing to call (the check is complete, or you cannot manage the identity). It is the same shape as nextActions: When sellers.nextCursor is present, call get_status again with include: ["setup"] and sellersCursor set to it for the next page. Send sellersCursor only with include: ["setup"]. A cursor that is malformed, stale because the seller list changed, or issued for another account is refused with VALIDATION_ERROR naming sellersCursor; start again from the first page. The text of the response lists every check and every seller on the page, each with the tool to call, and ends with the sellersCursor for the next page. For an advertiser, source: "saved_brand_link" means a saved branding snapshot. It does not assert that a published document is available now. A Seller’s identity.source: "storefront_config" likewise describes saved configuration. manifestUrl: null means that this read cannot identify a published URL. brandRef.domain is the saved brand domain as a lowercase host, without a scheme, port or path. The advertiser’s brand field keeps the domain exactly as it was saved. When no valid domain can be read from the saved value, brandIdentity is null and the rest of the advertiser still loads.

Confirm the Buyer’s operator

Use save_buyer_operator as an account administrator:
Every Buyer account is its own AdCP operating unit, so there is no scope to choose and no question about whether the account is “the whole company”. An organisation with one Buyer account has one unit; an organisation with several accounts has several. The unit’s name is the account name, and its id is a short code fixed when the identity is first saved:
  • Omit the code and one is generated from the account name, for example “DM - Restaurant Company Europe” becomes dm-restaurant-company-europe. If another account under the same operator domain already holds it, a short numeric suffix is added (-2, -3).
  • To choose a shorter code, send AdCP operator_unit with the id, for example "operator_unit": { "id": "rce" }. Use something your company already uses. Never use default, global or primary: no account is the default, global or primary one, and save_buyer_operator refuses those codes.
  • Saving again without a code keeps the saved one. The code never changes when the account is renamed.
get_status reports the saved unit as operatorIdentity.operator_unit, with name taken from the buyer account name.

Join or leave the seller-history co-op

save_buyer_operator also carries sellerHistoryCoop, the account’s membership in the seller-history co-op, how an account takes part in the data co-op of Section 6.3 of the Terms of Service. It starts false, and get_status reports the current value as operatorIdentity.sellerHistoryCoop. The setting is part of the operator identity because the operator that owns the account decides, so it takes the same administrator permission. To change only the membership, send the saved identity again unchanged with sellerHistoryCoop set. Joining shares the account’s judged results as aggregates, and leaving stops the account reading pooled history and sharing new buys while what it already shared stays in the pool, so either change needs the preview and confirmation below. The preview returns preview.sellerHistoryCoop with the before and after values and a link to the page that says what a member shares and gets. Show that to the person before confirming.

Confirm an identity change

Before replacing an existing domain or unit code, send the proposed values with preview: true. This explicitly requests action: "preview" without saving. Show the person the before and after values, including the unit code the save will use, and any loss of domain proof. After they confirm, repeat the same request without preview and with the returned preview.confirmationToken. If you did not name a code and another account under the same domain takes the previewed one before you confirm, the save is refused with CONFLICT and saves nothing. Preview again to see the new code, and confirm that one. In confirmed-v1, an unconfirmed replacement that does not request a preview returns isError: true with code: "CONFLICT" and saves nothing. A successful preview is returned only when you explicitly request one. A caller that attempts an unconfirmed replacement in this contract receives an error rather than a successful-looking result that preserves the old identity. The confirmation belongs to that account, current identity and requested change. A stale or different confirmation fails with CONFLICT; read and preview again. An identical retry with no new proof returns unchanged, preserves confirmation timestamps and domain proof, and does not create a second identity audit event. A successful write returns a resource receipt and its audit ID. Read get_status again to check the persisted domain, unit and proof. The first advertiser binding locks the operator identity. A locked correction requires support, rather than a different domain spelling or another account. One change is still open on a locked identity. An identity saved before every account had a unit can be locked by an advertiser while it has no unit: get_status reports locked: true and operator_unit: null. Repeat save_buyer_operator with the same operatorDomain to give it its unit, with an optional operator_unit code. No preview is needed. This changes the key sellers receive, so it is refused with CONFLICT while a seller account already holds the key without a unit: a complete-key Seller account, or an external seller account linked to one of this account’s advertisers. Request support through save_ask to move those accounts onto the unit. A verified account that still has no unit is not blocked from setup, but get_status offers choosing its code as a recommended next action (operator_unit, save_buyer_operator), because opening a seller account is refused without one. The v2 readiness check shows the same step as Choose account code on the operator_identity check, which stays complete. New Seller connections can then set up the account. A different domain on a locked identity still requires support.

Opening seller accounts needs an operating unit

Every Buyer account is its own operating unit. Before a seller account can be opened for this Buyer account, its operator identity must have an operator_unit. This holds on every route that opens a company seller account for a seller on complete-key accounts: AdCP sync_accounts, the v2 Buyer account sync, automatic activation, and the support operation that requests accounts for earlier per-user grants. An identity with no unit yet (saved before every account had one) is refused with the correctable ACCOUNT_SETUP_REQUIRED error and details.reason: "operator_unit_required". Nothing is created, and the same request succeeds once the unit is set. Set the unit with save_buyer_operator, as described above. If an advertiser has locked the identity and seller accounts already use it, request support through save_ask. Seller accounts that already exist are not changed. In a Buyer Account, call save_advertiser with only:
This previews a brand before you create an advertiser, the same way the advertiser form’s Look up brand does. It reads the brand’s AAO registry record of any kind, including community records, then enrichment data and the brand’s own website. identity.source is brand_json or hosted only when the brand publishes its own identity, which is what publicBrand: true requires; null means the name and logo came from another source. The lookup answers within about eight seconds. If it is still running at that point, the call returns an unresolved card with pending: true; call it again shortly and it picks up the same lookup. Media Company accounts that create their own advertisers use the same call. In a Seller Account, save_seller with only resolveBrand looks up the Seller’s own public identity. That lookup requires a published brand.json or an AAO-hosted brand identity and does not fall back to inferred branding. Both lookups are read-only. A Seller Account’s brand name, logo and logo background are refreshed from the same published identity when you save the operator domain with save_seller, whether or not the domain changed. If the brand has no published identity, or the lookup is slow or unavailable, the domain save still succeeds. When the domain is unchanged, the stored brand is left as it was. When the domain changes, any of the three that the new domain does not publish is cleared with the rest of the previous domain’s profile, so the old brand’s logo never stays beside the new domain. Previews never write. Inspect resolved, identity.brandRef, identity.source, name, logo and manifestUrl. identity.brandRef is an AdCP brand reference; it has no brand_id when the domain has no house brand id, or when the published id is not a valid AdCP brand id. An unavailable registry returns an error; a missing brand returns resolved: false and may supply a builder link. To create a Buyer advertiser that requires public branding, call save_advertiser:
This create operation does not accept identityContract; use that field only when correcting the brand of an existing advertiser. Keep the key and creation fields unchanged when retrying. A key reused for a different request is rejected. The creation receipt includes its audit event ID. Existing calls that omit publicBrand retain the normal brand-resolution behaviour, which may include inferred branding. If a brand-resolution source is rate-limited or temporarily unavailable while you create an advertiser, save_advertiser returns SERVICE_UNAVAILABLE instead of treating the brand as missing. Wait and retry the request; the error includes retryAfter in seconds when the source supplied one. No advertiser is created for that response. A missing-brand validation error means every resolution source answered without data. To correct an advertiser’s brand, supply identityContract: "confirmed-v1", advertiserId, brand, preview: true, and optionally publicBrand: true. An account administrator must review the returned preview and repeat the request without preview and with its top-level confirmationToken after the person confirms. An unconfirmed replacement in this contract without preview: true returns CONFLICT and saves nothing. A saved replacement returns advertiser.identityChangeReceipt with its audit ID and brand-link IDs. Read the advertiser again to verify brandIdentity. If brandIdentity is null, the saved link cannot be inspected safely. Request support with save_ask to repair that legacy record before replacing it. An identical brand-only retry does not rewrite the link. With publicBrand: true, it also checks that public identity is currently available and returns that lookup separately from the saved snapshot. It does not refresh the saved name, logo or document contents.
v3 can resolve public branding and link an advertiser to a resolved brand. It cannot create, edit or publish brand.json, choose who owns an AAO-hosted document, or refresh a saved snapshot in place. Use the domain publisher or the returned external builder for document changes. These responses report editingSupported: false. A public lookup is never domain proof.

Change an advertiser’s brand after first use

An advertiser’s brand can still change after its first campaign or seller-account binding. The change applies to future buys only. The advertiser keeps its ID, name, campaigns, ledger, measurement, reporting, creatives, labels and tracking, because none of them are tied to the brand.
  • Buys already sent to a seller keep the seller account they were booked under. Updates, cancellation, delivery reporting and creative sync for those buys stay on that account until the buy ends.
  • Draft and unsent buys go out under the new brand when they are sent.
  • Sellers hold their accounts by brand. The first buy under the new brand at each seller creates or finds an account for that brand, and the seller decides on it separately: an approval for the earlier brand does not carry over. Accounts held under the earlier brand are not changed, revoked or deleted.
  • Accounts you own on a platform, such as an ad account connected with OAuth, stay linked. Links to accounts a seller provisioned under the earlier brand are not used for buys under the new one.
  • Brand data follows the new brand: the effective brand profile, creative sessions started afterwards and property-targeting defaults. A creative session, campaign creative or media buy that saved its brand earlier keeps what it saved. Looking an advertiser up by brand domain matches the current brand only.
  • Currency and sandbox stay fixed. A different currency or sandbox state is a different advertiser.
  • A brand an advertiser has used stays reserved to it for as long as the advertiser exists, archived included, even after its last buy on that brand ends. Another advertiser cannot be created on it or moved onto it, and the refusal names the advertiser that holds it. Deleting an advertiser releases its brands.
  • Two exceptions to that reservation. An archived sandbox advertiser releases every brand it has used, the current one and earlier ones, so another sandbox advertiser can take one of them. Restoring the archived advertiser is then refused while another active sandbox advertiser holds one of those brands. An archived production advertiser keeps all of its brands.
  • Changing back reuses earlier seller accounts where their links still exist. An advertiser holds one active link per seller agent. If a newer link at the same seller agent replaced the link a seller provisioned under the earlier brand, changing back does not restore it: that seller account may need to be found or provisioned again. Seller accounts themselves are not deleted.
No proof of brand ownership is needed beyond what creating an advertiser for that brand needs. Sellers check the brand’s own brand.json, as they do for a new advertiser. Use the same confirmed flow as a correction: identityContract: "confirmed-v1", advertiserId, brand and preview: true, then the same request without preview and with the confirmationToken after the person confirms. Only an account administrator can make the change. For a brand change, the preview also returns impact, so the person can see what the change touches before confirming: The token is bound to the brand link the preview was computed from and to its complete impact, every buy and seller rather than only the ids the preview lists. If the brand changed after the preview, or a buy was sent to a seller since, the confirmation is refused as stale; preview again. A buy that was sent to a seller without a stored seller account would otherwise look up its account under the new brand, so the change stores that account first, from the brand it is still on, completed buys included. If a live buy’s account cannot be worked out with certainty, for example because its seller account is no longer linked to the advertiser, the change is refused and the error names the buy. Nothing is changed in that case: fix what the error says, then try again. A buy that has already ended (completed, canceled, rejected or failed) and whose account cannot be worked out does not block the change: it will not be updated or canceled again, so it is skipped and listed in the advertiser’s audit history. A later delivery or status read for that ended buy may then look its account up under the new brand. An advertiser that a seller reaches through external self-serve access cannot change its brand, because that access is pinned to the current brand and would be retired for good. Create a new advertiser for the new brand instead. The preview refuses it too. An advertiser that a seller has on its advertiser roster under its current brand also cannot change its brand yet. The seller’s roster matches the advertiser by brand, so the entry would stop resolving and the seller would see the advertiser as unresolved. The preview and the confirmation both refuse it. Create a new advertiser for the new brand, or ask the seller to remove the roster entry first. The raw v2 PUT for an advertiser has no preview, so it keeps refusing a brand change after first use. Use save_advertiser for this change.

Confirm the Seller’s operator and follow proof

Use save_seller as an account administrator:
For a replacement, include preview: true before any fields change. Review the previous domain, proof and profile values, then repeat without preview and with its top-level confirmationToken after the person confirms. An unconfirmed replacement in this contract without preview: true returns CONFLICT and saves nothing. Fields curated for the previous domain, including description, channels, membership status, website, brand name, logo and logo background, may be cleared. Description and channels can be supplied in the same request to replace those values; the other legacy profile fields are not writable in v3. An intervening identity or profile change requires a fresh preview. The older confirmOperatorDomainProfileReset flag alone does not replace a confirmation token in confirmed-v1; its earlier behaviour remains available to existing callers as described above. The save returns a receipt with its audit ID and, when present, the domain review ID. Saving the domain uses the existing verification service and human review queue. An already approved domain may verify immediately; otherwise the current review is visible through:
Inspect operatorDomainVerified and identity.domainProof.review. The review contains its ID, domain, status, request time, revision, decision time and ETA when assigned. Poll this same read after the human responds. PENDING is not proof; REJECTED requires a correction or support follow-up. Verification is complete when the persisted domain matches the intended domain and operatorDomainVerified is true. A repeated identical save does not duplicate the review. Apart from the brand name, logo and logo background described above, saving a Seller domain does not copy the public lookup’s document fields into Seller configuration. A domain-only save for the already saved domain returns unchanged; members can make that request without administrator write permission or a proof-review read. Actual domain changes require an administrator. Proof reads are cancellable and have a bounded wait. If a transient read failure returns SERVICE_UNAVAILABLE, retry get.

Request a person when proof or correction needs help

Show the person the proposed support request before filing save_ask:
Keep the returned askId. In a Buyer or Seller Account, poll it with get({ "kind": "ask", "id": "ASK_ID" }), follow the human’s instructions, then re-read identity. A filed or resolved ask does not itself verify a domain. Do not paste passwords, OAuth tokens or other secrets into chat. If support approves a Buyer domain, repeat save_buyer_operator with the saved domain to record that approval, then check get_status again. The save checks approved evidence separately; repeating domain text without that evidence cannot verify it. A DNS TXT record check runs from the account’s domain settings, not from v3. v3 can inspect the evidence and request human help. A Seller review with no current record, a rejected review, or a locked identity correction can use the same support path. Shared workflows covers ask states and follow-up.