Platform go-live
You complete these steps once for the buyer account:- confirm the domain of the company that runs the account (the Company identity step);
- choose the plan for this buyer account;
- accept the current terms;
- resolve any account hold;
- once choosing payment terms is available, choose the payment terms sellers are asked for before buying from a seller on consolidated billing (see Your organization’s payment terms); and
- add your billing details (payer name, street address, and country) in the Billing details step, which is open only while you can buy from a seller on consolidated billing and those details are missing.
Apostra generates the code 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 that code, Apostra adds a short numeric
suffix. You can type a shorter code of your own, such as rce; prefer one your
organization already uses, or a short, readable code that will stay meaningful.
Do not use default, global or primary (no account is the default, global or
primary one), a temporary display name, a seller’s account ID, or an Apostra
database ID. The code never changes when you rename the account. The buyer
account name is mutable display metadata; the billing-company name is separate
and does not identify the operating unit.
An account administrator confirms the identity. Before confirming, review the
other buyer accounts under the same operator domain. Buyer Setup lists the
identities visible in your account hierarchy for the domain you enter. Apostra
rejects an exact identity (domain and code) already claimed by another buyer
account. You can change the operator domain or account code after setup and
after connecting storefronts, until an advertiser account is created or bound
under that identity. Buyer Setup then reports the identity as locked. In AdCP
3.2, the operator domain and the operating-unit ID are advertiser natural-key
dimensions; pre-3.2 bindings still make the seller-visible operator domain
immutable. Changing either requires an advertiser identity migration rather
than an ordinary settings update.
Accounts under an organization that claims a domain. When your buyer
account sits under an organization whose company identity holds a domain, an
account that uses that same domain takes its domain proof from the
organization:
- The account is verified when the organization’s domain is approved or verified by DNS, and that approval covers every account under the organization that uses the domain. An approval for the account itself does not count, and staff ask for the approval on the organization instead.
- An account that proved the domain before the organization claimed it keeps that proof.
- Once any account using the organization’s domain has an advertiser, the organization’s domain is locked, because changing it would change every one of those accounts’ identity at sellers.
- An account that uses a different domain, or whose organization has not saved a company identity, confirms and proves its own domain as before.
adagents.json; that document belongs to seller authorization. Buyer setup also
does not require brand.json.
Buyer Setup always shows the current operator. A domain suggested from existing
account or work-email information is prefilled, but it is not silently treated
as your choice. The account code field is prefilled with a code generated from
the account name, such as dm-restaurant-company-europe. Keep it or type your
own, and the code you see is the code that is saved.
Accounts created before every account had an operating unit keep working on
their existing buying paths until their unit is assigned. Buyer Setup does not
block them; a complete AdCP 3.2 account key needs the unit, so new AdCP 3.2
provisioning waits for it.
Seller-history co-op
The operator identity also holds whether the account joins 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 off. An account administrator changes it withPATCH /api/v2/buyer/readiness/operator
and sellerHistoryCoop, or with save_buyer_operator on /mcp/v3. What a
member shares and gets, and how leaving works, is on that page.
Double-check your media partners
Before you create your first advertiser, Buyer Setup asks one question: Have you double-checked your media partners? Media partners are managed for the whole company, not advertiser by advertiser. The Review media partners button opens Media Partners. This is a reminder, not a go-live step. It never blocks creating an advertiser, and Apostra still starts account setup with media partners whether or not you open it. It shows as done once your company has accepted its media partners, which happens when it makes a choice about them on the Media Partners page. Buyer readiness returns this as a check with the idmedia_partners. It is
missing until your company has accepted its media partners, then complete,
and its isBlocker is always false, so it changes none of the readiness
status, capability, or destination answers. On /mcp/v3, get_status lists it
as a recommended next action that opens Media Partners.
Launch your first campaign
Once platform setup is complete, the next step is launching your first campaign. Your first campaign counts as launched once one of its media buys is placed. This is the step after setup, not a setup check: it never blocks anything, and it changes none of the readiness status, capability, or destination answers. Buyer readiness returns it asfirstCampaign. firstCampaign.launched says
whether the account has placed a media buy. Until it has, and once
platformReady is true, firstCampaign.action is Launch your first
campaign, which opens Campaigns (page: "campaigns"). While setup steps
remain, or once a buy is placed, action is null. firstCampaign itself is
null only when it could not be read for that request; try again.
On /mcp/v3, get_status lists the same step as a recommended next action,
first_campaign, that opens Campaigns.
Your next step on the Advertisers page
The Advertisers page shows one next step above your advertisers. While a setup step blocks buying, it names the first one and opens Buyer Setup. Once setup is complete and nothing has launched, it is Launch your first campaign and opens Campaigns. It is the same stepget_status puts first. The page shows
nothing when no step is left, or when the step could not be read in time.
If an API call requires Buyer Setup
On/mcp/v3, call get_status first. When
operatorIdentity.usableForBuying is false, an account administrator can call
save_buyer_operator with the real non-platform operatorDomain, and
optionally a short AdCP operator_unit code ({ "id": "rce" }); without one,
the account’s unit code is generated from its name. When locked is true,
follow the support action returned by get_status instead, unless the account
has no unit yet (operator_unit is null), which the same call can still assign.
To open the Buyer Setup page for a person, call open_page with
{ "page": "buyer_setup" }; the opening call changes nothing.
The v2 request, PATCH /api/v2/buyer/readiness/operator, takes the same operatorDomain
and optional operatorUnitId. It still accepts operatorScope: "specific_unit" from
older clients and generates the unit when you send no scope. It refuses
operatorScope: "whole_operator" with a 400:
Whole operator is retired; every buyer account is an operating unit. Send operatorScope: “specific_unit” with operatorUnitId, or omit operatorScope to use the unit generated from the account name.Nothing is converted for you: a request that used to save a whole-operator identity now fails until you send a unit or omit the scope. This is a deliberate exception to the rule that v2 only grows. The decision, in full: “v2 buyer
PATCH /api/v2/buyer/readiness/operator refuses operatorScope: "whole_operator"
with a 400. Whole operator is retired. Brian O’Kelley, 2026-10-22.” Reads are
unchanged and return what is stored. The v2 readiness response keeps operatorScope, scopeStatus and
scopeConfirmedAt as deprecated, read-only fields that report the stored scope:
an identity saved as whole_operator keeps reading that way until it is
converted to its own unit, and a saved or generated unit reads specific_unit.
Nothing new is ever saved as whole_operator, so the update response reports
specific_unit once the unit is saved. Readiness also returns suggestedOperatorUnitId, the code the account would get if you
saved it now. The tool confirms commercial identity only; it does not grant user
access or change the login organization.
Before that identity is claimed, you can still create, update, or archive a
test-only advertiser with
sandbox: true, through v3 save_advertiser, the v2
advertiser API, or the Create advertiser form. This exception applies only
to the operator-identity check: plan selection, current Terms, and other
readiness blockers still apply. Live advertisers continue to require the
complete buyer operator identity.409 with error
code BUYER_SETUP_REQUIRED when the account has no confirmed, non-platform
operator identity. For a missing identity, the exact structured details are
reason: "missing_operator_identity", readinessCheck: "operator_identity", setupStep: 1, and setupPage: "buyer_setup". This is
a correctable account-readiness task, not a seller outage: open Buyer
Setup, confirm the operator domain, then retry the request.
interchange.io for a missing buyer operator.
That would combine unrelated buyers under one seller-side natural-key account.
If a legacy profile explicitly contains that platform domain, the request uses
the same BUYER_SETUP_REQUIRED contract with details.reason: "platform_operator_not_allowed". Replace it with your organization’s operator
domain in Buyer Setup.
Changing or confirming the operator affects new discovery and provisioning,
but does not rewrite existing transactions. A historical media buy continues
to use the exact seller account persisted when the buy was created, including
for status, creative re-sync, update, cancellation, and delivery operations.
The same identity gates account linking. A production entry on
POST /api/v2/buyer/storefront-accounts/sync (or the
sync_buyer_storefront_accounts tool) must name your confirmed operator
domain as operator; a different domain returns HTTP 403 with
ACCESS_DENIED and details.reason: "operator_identity_mismatch", and a
missing identity returns the BUYER_SETUP_REQUIRED contract above. A
sandbox entry (sandbox: true) is fenced off from production spend and may
name any operator.
Who decides your account request
A seller decides your account request the same way whichever way it arrives:sync_accounts on the seller’s AdCP endpoint,
POST /api/v2/buyer/storefront-accounts/sync or the
sync_buyer_storefront_accounts tool, or an account Apostra opens for you
automatically.
- A seller that routes accounts to its own sales agent (a Listing whose
only source is that agent) forwards the request, including any
payment_terms, to the agent, and the agent approves or rejects it. The seller does not review it in Apostra. The agent must accept the terms you requested or reject the account. Apostra records the terms you requested, and the account reports inpayment_termsthe terms the agent confirms. A new account the agent offers on other terms is treated as a refusal: the account is not activated and waits for you to review the seller’s terms. An existing account the agent keeps on other terms stays usable, but it shows a warning naming both the terms you requested and the terms the agent kept, until the agent reports the terms you requested. If the agent cannot take account requests, the request fails and nothing is created: the buyer API returns HTTP422withCAPABILITY_NOT_SUPPORTEDand adetails.reasonsuch asaccount_resolution_authority_missing, and the AdCP endpoint returnsCONFIGURATION_ERROR. Retrying does not help until the seller fixes its agent. - Every other seller applies its account approval setting in Apostra: the request is approved automatically or waits for the seller to review it.
status: "pending_approval".
Check it later with GET /api/v2/buyer/storefront-accounts or the
list_buyer_storefront_accounts tool. On the seller’s AdCP endpoint,
sync_accounts answers with the account’s own row, status: "pending_approval"
and a setup message, rather than a task; call list_accounts on that endpoint
to see the seller’s decision.
On a storefront that has not moved to complete AccountKey mapping, an approved account belongs to your buyer organisation: any colleague or service token of the same buyer can use it, and nobody outside your organisation can.
When a direct AdCP 3.0 or 3.1 storefront asks for account setup
After a storefront moves to complete AccountKey mapping, a direct AdCP 3.0 or 3.1sync_accounts call can still read an approved account that already
belongs to its credential. It cannot create a new account on that older wire
format. A new direct request returns ACCOUNT_SETUP_REQUIRED with
details.reason: "complete_key_account_setup_required".
Create the account through your authenticated V2 buyer account, then retry the
direct call after the seller has decided it. Use either the REST request
POST /api/v2/buyer/storefront-accounts/sync or the buyer MCP tool
sync_buyer_storefront_accounts. Both take the same account request; target
the storefront with its V2 storefrontId and send the brand, your confirmed
operator domain for a production request, and the billing party:
sandbox: true
only for a test account that cannot be used for production spend. See
Payment terms for the optional per-seller request field and
the billing requirements for operator and advertiser.
Address your approved account from a direct AdCP 3.0 or 3.1 agent
Once a seller has moved to complete AccountKey mapping, a direct agent can use two kinds of approved account. Theaccount_id itself says which kind:
- Company accounts have an
account_idthat startsseller_account_v1_. The seller approved them for your verified buyer organisation and an advertiser, and any human or service token currently authorised for that organisation and advertiser can use them.sync_buyer_storefront_accountsandlist_accountsreturn them. - Credential accounts are the accounts that one credential of yours was approved for before the seller moved. Their
account_idstartssf_. They stay available to that exact credential and to nobody else: another user or service token of the same company does not inherit them, and Apostra does not convert them into company accounts.
account_id alone. An AdCP account is one of two exclusive shapes, never both:
account_id together with brand or operator inside account is rejected before any account lookup with VALIDATION_ERROR, field: "account", and details.issues[] naming /account and the additionalProperties rule. It is a malformed request, not a missing account. To tell Apostra which brand you are buying for, send the top-level brand reference as AdCP defines it. Its domain must match the approved account’s brand.
On a seller in complete-key mode these calls resolve the same approved account, through the lane its account_id belongs to: list_accounts, get_products, get_account_resources, sync_creatives, create_media_buy, get_media_buys, update_media_buy (including cancellation), and get_media_buy_delivery. An id that starts seller_account_v1_ is only ever looked up as a company account. If it is unknown, malformed, or not yours, the call fails; Apostra never retries it as a credential account, and never reads a sf_ id as a company account.
Each company-account call checks again, at that moment, that:
- the account belongs to your verified buyer organisation and is approved by the seller;
- the request selects the advertiser the account is scoped to, with the
x-scope3-seat-idheader (or an API key that is already bound to it); - the credential is a human user with Premium or Admin access to that organisation, or a write-capable service token for that organisation and advertiser, and has not been revoked; and
- your buyer account is currently eligible.
list_accounts returns your company accounts first, then the calling credential’s own credential accounts, behind one pagination.cursor. A credential with no selected advertiser or no human or service-token actor lists its credential accounts only. A caller that does present that authority and is refused gets the refusal, not a shorter list. GET /api/v2/buyer/storefront-accounts and the list_buyer_storefront_accounts tool list the same way on a seller in complete-key mode: company accounts first, then the calling credential’s own credential accounts, behind one cursor. A cursor that did not come from this listing is rejected with a validation error.
A new buy needs an account that is settled before anything is written. Send the account_id. A brand and operator is accepted only when it is exactly one credential account that the calling credential already holds (same brand, operator and sandbox flag, nothing more, and the grant is active); the buy is then written under that credential account. Any other brand and operator, and a missing account, returns ACCOUNT_SETUP_REQUIRED and writes nothing. A partial key is never completed into a company account.
If a call fails closed, Apostra does not fall back to another account or to every account the customer owns.
Sellers that are not in complete-key mode keep the released per-credential account behaviour for every call above.
An account grant says whether the seller will transact with you. It does not
say whether Apostra uses that seller for a given advertiser. A
GET /api/v2/buyer/storefront-accounts request (or the
list_buyer_storefront_accounts tool) that names an advertiser with
advertiserId, or selects one with the x-scope3-seat-id header, also returns
ext.interchange.advertiser_activation: seller_on (whether product discovery
and new media buys use this seller for that advertiser) and reason (the
control that decided it). A named advertiser you cannot read is refused with
403, and 503 means access could not be checked right now. A seller can have an active grant and still be off for the
advertiser; turn it on with
Update advertiser Seller preference.
The field is omitted when the request names and selects no advertiser, when
the advertiser belongs to another account (a sibling account in your
organization, or an organization that delegated it), or when Apostra cannot
read the advertiser or the decision; the grant list still returns.
Billing modes and the business entity payload
Eachsync_accounts entry names a billing mode: agent (Interchange
invoices on your behalf; no additional payload needed), operator, or
advertiser (the storefront invoices your operator or advertiser directly).
operator and advertiser entries require a billing_entity — the AdCP
BusinessEntity payload with your legal name and, as applicable, tax/VAT/
registration ids, a postal address, billing contacts, and bank details:
billing_entity.bank is write-only: send it to provide payment coordinates,
but it is never echoed back on a sync_accounts or list_accounts response —
the seller stores it and confirms receipt without returning it.
A storefront only accepts the billing modes it has published support for. An
entry naming an unsupported mode returns HTTP 400 with
BILLING_NOT_SUPPORTED and details.supported_billing listing the modes the
storefront actually accepts:
Payment terms
Payment terms can be requested per seller account, and separately for your whole organization. They are two different settings with different values:- Per seller account (
sync_accounts). Each entry in async_buyer_storefront_accountscall (POST /api/v2/buyer/storefront-accounts/sync) can set its own optionalpayment_terms. Each call targets one seller storefront (target.storefrontId), so one request can carry different terms for different sellers. Allowed values:net_15,net_30,net_45,net_60,net_90, orprepay. Omitpayment_termsto accept the seller’s default terms. - Organization level (
paymentTerms). One choice for the whole organization, set with Update billing info or the V3save_billingtool. Allowed values:net_15,net_30,net_45,net_60, ornet_90.prepayis not an organization-level value. Apostra uses this choice when it opens a consolidated-billing account for you; see Your organization’s payment terms. - The V3 hosted-agent tools cannot set per-seller terms.
save_connectionhas no payment-terms field and there is no V3sync_accountstool. The only payment-terms write in the V3 tools is the organization-levelsave_billingpaymentTerms. To request different terms from one seller, usesync_buyer_storefront_accountsor its REST route.
sync_accounts entry request payment_terms. The protocol does not
let a seller silently swap in different terms: the seller accepts the requested
terms or rejects the account. The seller sees the requested terms when it
reviews the account and can only accept or reject; it cannot edit them.
The requested terms go to the seller with the account request:
- The seller reviews them. Approving the account accepts the terms you
requested, and the account then reports them in
payment_terms. On a storefront that routes accounts to the seller’s own sales agent, that agent decides instead; see Who decides your account request. There is no counter-offer: if the terms don’t work for the seller, the seller rejects the account. - Net 60 or shorter can be approved automatically. Unless the seller has
chosen to review every new account, a storefront approves a request for
net_60or shorter terms (orprepay) without a person reviewing it. A seller can lower that limit. A request for longer terms, such asnet_90, always waits for the seller to review it, so it can take longer to approve. - You can change the terms while the request is pending. Send the same
account again with different
payment_termsand they replace the earlier ones; that account’s row returnsaction: "updated"and the seller reviews the new terms. - A decided account keeps its decision. Once the seller has accepted or
rejected the account, a request naming different terms changes nothing. That
account’s row returns
action: "failed"with the AdCP errorPAYMENT_TERMS_NOT_SUPPORTED, and the account keeps its status and its terms. Other entries in the same request are unaffected. To change the terms on an accepted account, agree them with the seller directly.
Your organization’s payment terms
Your organization chooses the payment terms Apostra asks sellers for:net_15,
net_30, net_45, net_60, or net_90. Until you choose, net_60 applies.
Set the choice with paymentTerms in
Update billing info; it applies
to every advertiser in the organization. Like the rest of this section, it is
available once requesting terms is available.
Every account request for an agent-billed, non-sandbox account carries these terms to the seller, whichever seller it is, unless the request names its own payment_terms.
Choosing terms is a go-live step for consolidated billing, so no
consolidated-billing buy is placed on terms nobody chose. Until an
organization administrator has chosen:
- buyer readiness shows a Payment terms check (
payment_terms) that is not complete, and it blocks go-live when you have sellers on consolidated billing; - a seller on consolidated billing shows
needs_commercial_setup, and a buy from it is refused with thepayment_termsblocker; and - direct-billed sellers are not affected.
net_60 is pre-selected and the button reads Accept
Net 60; accepting it counts as choosing, and nothing is recorded until an
organization administrator does. Once chosen, the terms can be changed but not
cleared, so paymentTerms: null is refused with a validation error and the
recorded choice stays in place.
If you have not chosen and a media partner is waiting on your terms, the Media
Partners page shows Confirm your payment terms. One click records net_60,
the default, as your organization’s choice and resumes the held setup. It
records the default only; to choose other terms, use Buyer Setup. Only an
organization administrator can confirm, and Apostra never records terms for you
on its own.
Organizations that already had active consolidated-billing seller accounts or
buys when this step became required on 11 October 2026 have net_60 recorded
as their choice, so nothing is held for them. They can change it like any
other choice.
When Apostra opens a consolidated-billing account for you with a seller (for
example, when you turn a seller on for an advertiser or buy from a seller for
the first time), the request asks for your organization’s terms. Direct-billed
and sandbox account requests do not carry them:
- Longer terms can mean more rejections. Sellers carry the credit risk on
their accounts, so some decline longer terms. On storefronts Interchange
hosts or manages,
net_60or shorter can be approved automatically, whilenet_90waits for the seller to review it. - Decided accounts keep their terms. Changing your choice applies to accounts opened afterwards. An account a seller has already accepted or rejected keeps that decision and its terms; an accepted account keeps working exactly as before.
- A seller can refuse your requested terms. The account request then fails for that seller, and the connection reports that the seller does not accept your terms. Review the seller’s terms before explicitly requesting an account on those terms, or leave that seller disconnected. Apostra does not retry the request on the seller’s default terms.
account_id must
belong to the authenticated buyer on that storefront. A missing buyer grant or
an ID belonging to another buyer returns the structured AdCP error
ACCOUNT_NOT_FOUND with details.reason: "account_not_authorized_for_buyer"; it is not reported as a missing
storefront account context. Retrieve an authorized account with
list_accounts, or complete the seller’s account-linking flow, before retrying.
Buyer Setup returns derived capability verdicts rather than a writable Account
mode. Before Organization proof, plan selection, and Terms, the Account can use
bounded demo and onboarding surfaces. After those steps it can perform real
non-spend work. Spend additionally requires the media-buying product entitlement.
Seller-direct transactions need nothing further from Apostra.
Consolidated-billing transactions additionally need your organization’s billing
details: a payer name, street address, and country, so Apostra can invoice you.
They never need a card or an Apostra credit line, because Apostra takes no credit
risk on the seller’s media. An organization that already has a verified card or an
Apostra credit line on file can keep buying while it adds its billing details.
Account holds block every capability.
Confirming or changing the buyer operator does not change your WorkOS
organization, sign-in, invitations, SSO, account membership, billing company,
advertiser, or brand domain.
Destination go-live
Every seller or platform then shows only its own remaining requirement:- A credential-free AdCP seller requires no connection step.
- An official adapter may require a free provider connection, account choice, and advertiser mapping.
- A seller can be temporarily unavailable even when your connection is healthy.
- Direct-billed sellers and platforms bill the operator or advertiser and do not use an Apostra rate card or payment method for that route.
- A seller on consolidated billing requires active media pricing supported by
the current pricing engine and your billing details before live spend. Add
them in Plan & Billing → Payment & invoices. Until they are complete, the
buy is refused with the
billing_detailsblocker, readiness listsBILLING_DETAILS, andcommercial.billingDetailsCompleteisfalse. Readiness no longer reportsPAYMENT_AUTHORITYor thepayment_authorityblocker. Treat any blocker value you do not recognize as blocking. A child account automatically uses the media pricing on its billing organization; the account-delegation placeholder does not control that inheritance. Once choosing payment terms is available, your organization must also have chosen them; see Your organization’s payment terms.