> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Buyer setup and go-live

> Confirm your company once, then see what each seller or buying platform needs. Operator identity, the BUYER_SETUP_REQUIRED refusal, payment terms, seller accounts and child accounts.

Buyer setup separates your organization's readiness from the setup each seller or buying
platform needs. You complete the first part once for a buyer account. Every seller then
shows only its own remaining requirement.

Call `get_status` to read it, and `open_page` with `{ "page": "buyer_setup" }` to open the
Buyer Setup Page for a person. [Identity and brands](https://docs.apostra.com/v3/identity-setup.md) shows the calls
that set the operator identity and read the whole checklist.

If Apostra invites you to a new buyer account, the setup email goes to your named
address. Accept the invitation and verify that email to join. The invitation opens the
account setup path, and your organization still completes its identity, Terms and other
readiness steps before live buying.

## Platform go-live

These steps are done once for the buyer account:

* confirm the domain of the company that runs the account (**Company identity**, the
  `operator_identity` check);
* accept the current Terms (`terms`);
* resolve any account hold (`account_standing`);
* choose the payment terms sellers are asked for, before buying from a seller on
  consolidated billing (`payment_terms`); and
* add your billing details: a payer name, street address and country. This step is open
  only while you can buy from a seller on consolidated billing and those details are
  missing (`billing_details`).

These facts unlock real non-spend work such as connections, proposals and campaign setup.
Billing details matter only when a transaction's seller bills through Apostra on
consolidated billing. Apostra does not grant or manage a buyer credit line. Sellers decide
credit on their own terms, on their own media.

What the account can do follows from these facts. Apostra derives it and you cannot set
it:

| Capability | What it needs |
| - | - |
| Demo and onboarding | An eligible buyer account with no account hold. |
| Real non-spend work | Also a confirmed company identity whose domain the organization has proved, a plan on the account, and the current Terms accepted. |
| Spend | Also the media-buying product entitlement. |
| Spend through consolidated billing | Also billing details (or a verified card or credit line the organization already had) and chosen payment terms. |

Seller-direct transactions need nothing further from Apostra. An account hold blocks every
capability. Confirming or changing the operator does not change your WorkOS organization,
sign-in, invitations, SSO, account membership, billing company, advertiser or brand
domain. Choosing an IU plan is not a buyer-readiness requirement, and the media rate card
used to price a buy is separate from the Organization IU Rate Card.

You can connect destinations, inspect accounts and view mirrored campaigns without
charge. "Can buy now" means the capability is allowed and at least one destination's own
requirements are complete.

## Company identity

The **Company identity** step asks for the domain of the company that runs the account.
Sellers use it to recognize you. Sandbox advertisers do not need this step, so you can
create, update or archive a test-only advertiser (`sandbox: true`) before the identity is
confirmed. Plan, Terms and the other readiness checks still apply. Live advertisers and
real buying need the complete identity. Once you have confirmed the domain and created your
first live advertiser, the domain and the account code lock, and changing them takes an
identity migration through support.

In AdCP terms the company is the **operator** and each buyer account is one **operating
unit** of it. Every buyer account is its own unit. There is no "whole company or one team"
choice: an organization with one buyer account has one unit, and an organization with
several accounts has several. Together the domain and the account's unit code form its AdCP
operator identity:

| Part | What it is |
| - | - |
| Operator domain | The domain of the company that runs the account. |
| Operating unit `id` | A short code fixed when the account's identity is first saved. |
| Operating unit `name` | The buyer account name. |

Apostra generates the code from the account name, so "DM - Restaurant Company Europe"
becomes `dm-restaurant-company-europe`. If another account under the same operator domain
already holds the code, Apostra adds a numeric suffix (`-2`, `-3`). You can send a shorter
code of your own, such as `rce`. It must start with a letter or number and use only letters,
numbers, dot, underscore, colon, slash and hyphen, up to 255 characters. Do not use
`default`, `global` or `primary`, which `save_buyer_operator` refuses, because no account is
the default, global or primary one. Do not use 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 display text, and the billing company's name is separate and does not
identify the unit.

An account administrator confirms the identity with `save_buyer_operator`. Before
confirming, review the other buyer accounts under the same operator domain. Apostra rejects
an exact identity (domain and code) that another buyer account already claims. You can
change the domain or the code after setup, and after connecting storefronts, until an
advertiser account is created or bound under that identity. `get_status` then reports the
identity as `locked`. In AdCP 3.2 the operator domain and the operating-unit ID are
advertiser natural-key dimensions, so changing either needs an identity migration, not an
ordinary settings update. [Identity and brands](https://docs.apostra.com/v3/identity-setup.md#confirm-the-buyers-operator)
has the preview and confirmation a change needs.

`get_status` always shows the current operator. A domain suggested from existing account or
work-email information is prefilled, but it is never silently treated as your choice, 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 a unit is assigned. A complete AdCP 3.2 account key needs the unit, so
new AdCP 3.2 account provisioning waits for it.

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

Apostra compares the operator domain with account membership and the verified organization
domain. The organization must prove control before real operations are available. AAO
corporate metadata can suggest or classify the organization, but a public AAO record is not
proof of ownership. A buyer operator does not publish `adagents.json`, which belongs to
seller authorization, and buyer setup does not require `brand.json`. See
[Which domain is which](https://docs.apostra.com/v3/domains.md) for how a domain is approved.

### Seller-history co-op

The operator identity also holds whether the account joins the
[seller-history co-op](https://docs.apostra.com/v2/concepts/seller-history-co-op.md), 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 with `sellerHistoryCoop` on `save_buyer_operator`. What a member shares and gets,
and how leaving works, is on that page.

## If a call needs Buyer Setup

Product discovery and other new buying operations are refused with HTTP `409` and the error
code `BUYER_SETUP_REQUIRED` when the account has no confirmed operator identity that is not
the platform's own. This is a correctable account task, not a seller outage. The refusal
carries these `details`:

```json theme={null}
{
  "reason": "missing_operator_identity",
  "readinessCheck": "operator_identity",
  "setupStep": 1,
  "setupPage": "buyer_setup"
}
```

Open Buyer Setup, confirm the operator domain, then retry the request. On V3, call
`get_status` first. When `operatorIdentity.usableForBuying` is false, an account administrator
can call `save_buyer_operator` with the real `operatorDomain`, and optionally a short
`operator_unit` code such as `{ "id": "rce" }`. When `locked` is true, follow the support
action `get_status` returns instead, unless the account has no unit yet (`operator_unit` is
null), which the same call can still assign.

Apostra never substitutes `interchange.io` for a missing buyer operator, because that would
combine unrelated buyers under one seller-side account. A buyer with no registered domain
gets this refusal and is not given a default operator. If a legacy profile explicitly holds
the platform domain, the request is refused the same way with `details.reason:
"platform_operator_not_allowed"`. Replace it with your organization's operator domain.

A seller account that cannot be opened because a company account has no approved
complete-key account is also reported as `BUYER_SETUP_REQUIRED`, with `details.reason:
"complete_key_account_setup_required"`; see
[Seller accounts and the account key](https://docs.apostra.com/v3/buyer-setup.md#seller-accounts-and-the-account-key).

Changing or confirming the operator affects new discovery and account provisioning. It does
not rewrite existing transactions. A historical media buy keeps using the exact seller
account recorded when it was created, for status, creative re-sync, update, cancellation and
delivery.

## Double-check your media partners

Before you create your first advertiser, setup asks one question: **Have you double-checked
your media partners?** Media partners are managed for the whole company, not advertiser by
advertiser. This is a reminder, not a go-live step. It never blocks creating an advertiser,
and it shows as done once your company has made a choice on the Media Partners page. In
readiness it is the `media_partners` check, which is `missing` until then and `complete`
after, and is never a blocker. `get_status` lists it as a recommended next action that calls
`open_media_partners_page`.

## Launch 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, and it never blocks anything. With `include: ["setup"]`,
`get_status` returns `setup.firstCampaign`. `launched` says whether the account has placed a
media buy. Until it has, and once `platformReady` is `true`, `action` is a call to
`open_campaigns_page`. `firstCampaign` is `null` only when it could not be read for that
request, so try again. `get_status` lists the same step as the recommended next action
`first_campaign`.

## Seller accounts and the account key

A seller holds an account for you, keyed by your brand and operator (and operating unit).
Apostra can open that account for you automatically as part of connecting a seller and buying
from it, and a direct AdCP agent can ask a storefront for one with `sync_accounts`.

### Who decides your account request

A seller decides the request the same way whichever way it arrives.

* **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. 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. A new account the agent offers on other terms is
  treated as a refusal: it is not activated and waits for you to review the seller's terms.
  An existing account the agent keeps on other terms stays usable and shows a warning that
  names both sets of terms. If the agent cannot take account requests, nothing is created and
  the request fails with `CAPABILITY_NOT_SUPPORTED` and a `details.reason` such as
  `account_resolution_authority_missing`. 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. By default Apostra approves
  an account that asks for net 60 or shorter terms, prepay, or no particular terms, and a
  request for longer terms waits for review. See
  [Why approve and map buyers](https://docs.apostra.com/v3/seller-why-approve-and-map-buyers.md).

A request that is still waiting comes back with `status: "pending_approval"`. On a
storefront's AdCP endpoint, `sync_accounts` answers with the account's own row, with
`status: "pending_approval"` and a `setup` message. Call `list_accounts` on that endpoint to
see the seller's decision.

### Payment terms: per seller and per organization

Payment terms can be requested for one seller account and, separately, for your whole
organization. They are two settings with different values.

* **Per seller account.** Each `sync_accounts` entry can carry its own `payment_terms`:
  `net_15`, `net_30`, `net_45`, `net_60`, `net_90` or `prepay`. Omit it to accept the seller's
  default terms. The seller accepts the requested terms or rejects the account. It cannot
  counter-offer or edit them. You can change the terms while the request is pending by
  sending the same account again, and the seller reviews the new terms. After the seller has
  accepted or rejected the account, a request naming different terms changes nothing: that
  row returns `action: "failed"` with the AdCP error `PAYMENT_TERMS_NOT_SUPPORTED`, and the
  account keeps its status and terms. To change terms on an accepted account, agree them with
  the seller directly. The V3 tools have no per-seller payment-terms field.
* **Per organization.** One choice for the whole organization: `net_15`, `net_30`, `net_45`,
  `net_60` or `net_90`. `prepay` is not an organization-level value. An organization
  administrator sets it with `paymentTerms` on `save_billing`, and Apostra asks sellers for
  these terms when it opens a consolidated-billing account for you. Until you choose, `net_60`
  applies and `paymentTermsChosen` reads `false`. Once chosen, the terms can be changed but not
  cleared: `null` is refused.

Choosing organization terms is a go-live step for consolidated billing, so no
consolidated-billing buy is placed on terms nobody chose. Until an administrator has chosen,
the `payment_terms` check is incomplete and 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 the `payment_terms` blocker. Direct-billed sellers and sandbox
accounts are not affected. If you already connected a seller on consolidated billing, Apostra
holds that seller-account setup until you choose, then resumes it automatically.

The choice applies to accounts opened afterwards. An account a seller has already accepted or
rejected keeps that decision and its terms. Longer terms can mean more rejections, because
sellers carry the credit risk on their accounts and some decline longer terms. A seller can
refuse your requested terms, and Apostra then does not retry the request on the seller's
default terms. [Choose payment terms for consolidated billing](https://docs.apostra.com/v3/tool-reference.md#choose-payment-terms-for-consolidated-billing)
and [Billing: plan and invoices](https://docs.apostra.com/v3/billing-plan-and-invoices.md#payment-terms-a-seller-refused)
cover the calls and what happens after a refusal.

### Billing modes

Each `sync_accounts` entry names a `billing` mode: `agent` (Apostra invoices on your
behalf; nothing more is needed), `operator`, or `advertiser` (the storefront invoices your
operator or advertiser directly). `operator` and `advertiser` need a `billing_entity`, the
AdCP `BusinessEntity` payload with your legal name and, as they apply, tax, VAT or registration
IDs, a postal address, billing contacts and bank details. `billing_entity.bank` is write-only:
the seller stores it and confirms receipt, and no read returns it. A storefront accepts only
the modes it has published support for. A mode it does not list fails that account's row with
`BILLING_NOT_SUPPORTED`, and `details.supported_billing` lists the modes it accepts.

### The account key

After a storefront moves to complete AccountKey mapping, a direct agent uses two kinds of
approved account, and the `account_id` says which:

* **Company accounts** have an `account_id` that starts `seller_account_v1_`. The seller
  approved them for your verified buyer organization and an advertiser. Any human or service
  token currently authorized for that organization and advertiser can use them.
* **Credential accounts** were approved for one credential before the seller moved. Their
  `account_id` starts `sf_`. 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.

Send the `account_id` alone. An AdCP `account` is one of two exclusive shapes, never both:

```json theme={null}
{ "account": { "account_id": "seller_account_v1_0123456789abcdef0123456789abcdef" } }
```

```json theme={null}
{ "account": { "brand": { "domain": "brand.example" }, "operator": "buyer.example" } }
```

A request that sends `account_id` with `brand` or `operator` inside `account` is rejected
before any account lookup. To say which brand you buy for, send the top-level `brand`
reference AdCP defines, and its domain must match the approved account's brand.

On a seller in complete-key mode, `list_accounts`, `get_products`, `get_account_resources`,
`sync_creatives`, `create_media_buy`, `get_media_buys`, `update_media_buy` and
`get_media_buy_delivery` resolve the same approved account through the lane its `account_id`
belongs to. An id that starts `seller_account_v1_` is only ever looked up as a company
account, and Apostra never retries a failed lookup as a credential account or reads an `sf_`
id as a company account. A company-account call checks again each time that the account
belongs to your verified organization and is approved by the seller, that the request selects
the advertiser the account is scoped to, and that the credential is a human with Premium or
Admin access to the organization or a write-capable service token for it. A credential
account needs the grant for the calling credential to be active. A call that fails closed
never falls back to another account.

| Situation | Response |
| - | - |
| A company or credential account that does not exist, belongs to another organization or credential, or is scoped to a different advertiser | `ACCOUNT_NOT_FOUND`, `details.reason: "account_not_authorized_for_buyer"`. The answer is the same for each, so an id reveals nothing. |
| A company account with no advertiser or no authenticated actor on the request | `AUTH_REQUIRED`, `details.reason: "complete_account_authority_required"` |
| A credential account whose grant is pending, rejected, suspended or closed | `AUTH_REQUIRED`, `details.reason: "account_grant_inactive"` |
| A new brand or operator through a direct AdCP 3.0 or 3.1 `sync_accounts`, or a buy with a brand and operator that is not your credential account | `ACCOUNT_SETUP_REQUIRED`, `details.reason: "complete_key_account_setup_required"` |
| A company-account booking that the seller reviews manually | `INVALID_REQUEST`, `details.reason: "complete_key_account_approval_unsupported"` |

A direct AdCP 3.0 or 3.1 `sync_accounts` call can still read an approved account that
belongs to its credential, but it cannot create a new account on that older wire format.
Use AdCP 3.2 or later, which carries the full key including the operating unit.

An account grant says whether the seller will transact with you. It does not say whether
Apostra uses that seller for a given advertiser. Turning a seller on for an advertiser is a
separate choice.

## Child accounts

An organization administrator can create a Buyer child account under the selected
organization with a review and a request. Both tools run in the organization account.

1. Call `review_buyer_child_account` with the parent organization's account id (`parentId`)
   and the proposed `name`. It is read-only and creates nothing. It returns the proposed
   account (`role: "BUYER"`), the operator, the parent's `capacity` (`consumed`, `remaining`,
   `limit`, `allowed` and any `denialReasons`), whether the organization's plan covers a
   Buyer account (`planCoverage`, with a `refusal` that names the plan it needs when it does
   not), what changes (`accessChanges`: parent administrators inherit access to the child,
   with no new memberships or invitations; `otherChanges`: no feature flags and no media
   buys), `canRequest` and any `blockers`. `transactionReadiness` is always `not_verified`.
   Show the review to the person.
2. Call `request_buyer_child_account` with the same `parentId` and `name` and a new
   `idempotencyKey` (a UUID). Nothing is created until an organization administrator approves
   the request on the Apostra site. The result is `approval_required` with a link to show the
   person. Repeat the call with the same key and name to read the outcome.

Creating the account is not transaction readiness. The new account still completes its own
setup, starting with its company identity. [Run Apostra for several client accounts](https://docs.apostra.com/v3/several-client-accounts.md)
compares a child account with an advertiser in one account.

## Related

* [Identity and brands](https://docs.apostra.com/v3/identity-setup.md) for the calls that confirm the operator.
* [Which domain is which](https://docs.apostra.com/v3/domains.md) for how a domain is approved.
* [Plan and billing](https://docs.apostra.com/v3/plan-and-billing.md) for Terms, plan and billing details.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.