> ## 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 Account Mapping

> Review seller account identities, verified buyer owners, and private inventory-source coverage

Buyer Account Mapping gives a seller one account for each complete AdCP
AccountKey and shows the verified buyer organisation that owns it. The seller can
privately see whether each inventory source has a current mapping. Operator and
brand still group the list for navigation, but they do not identify an account or
carry an approval on their own.

## Where to find Buyer Account Mapping

In the seller workspace, open **Buyers**, then select **Buyer Account
Mapping**. This opens the full mapping Page without requiring a chat request.

For one buyer relationship, open **Advertisers**, select its External
advertiser row, then open **Account**. That opens the same relationship's
focused account-setup case.

Inventory Sources and ad-server connection settings manage the source
connection and its roster health. Buyer account mapping is configured from
Buyer Account Mapping or the focused Account case, not from the source
connection.

<Note>
  The complete-key experience is staged behind a customer cutover and is off by
  default. Until a storefront is enrolled, the Page keeps the released
  relationship-based view and six-column v1 feed. On the complete-key path, the
  same import Task uses the versioned v2 feed format. A missing or failed cutover
  decision does not switch the Page to an empty exact-account view.
</Note>

Open the portable Page with the storefront MCP tool:

```json theme={null}
{
  "name": "get_seller_accounts",
  "arguments": {}
}
```

## What is canonical

An account is identified by its storefront and complete AccountKey:

* brand domain, optional brand ID, and optional country set;
* operator domain and optional operator-unit ID;
* optional fixed currency and buyer-selected timezone; and
* sandbox value.

The Page shows every field, including absent optional fields, alongside the
verified buyer organisation. A CRM record, GAM advertiser, FreeWheel reference,
operator, brand, user credential, or another native ID can support the account,
but none replaces this identity.

An omitted country qualifier means **all countries**. An explicit country set is
preserved as part of the AccountKey, so `US` is not the same account as all
countries. Older relationship rows whose country scope is unknown are
setup-incomplete: they cannot be shown, approved, or used as complete-key
accounts. The `sync_accounts` wire type has no country field; omit it there and
use the reviewed v2 mapping flow when recording an explicit country set.

This keeps two native accounts with the same literal ID separate. For example,
`1234` under `gam-primary` and `1234` under `freewheel-ctv` are different source
mappings even when both support the same buyer relationship.

## Account authority during the complete-key cutover

For a storefront enrolled in the complete-key cutover, an opaque account ID is
a reference, not a credential. Every list, discovery, creative-sync, and
media-buy operation rechecks the approved account's verified buyer organisation,
advertiser scope, active seller decision, and the current human or service-token
authority before contacting a source. Authorised colleagues can use the same
approved account while audit records the actor that performed each action.

Removing the owner, seller decision, or actor authority blocks the next
operation. A pending task or deferred retry repeats those checks when it runs;
it does not trust the credential that originally created the work. Another
organisation cannot use the account, including by supplying its opaque ID.

The older relationship-based view remains available only while a storefront is
not enrolled. It is never treated as a complete-key approval, and legacy v1
rows cannot be listed, approved, or executed as AdCP 3.2 accounts.

## How account requests resolve

Each `sync_accounts` request has one resolution authority. A storefront that
builds or mixes inventory resolves the request through its own intake policy. A pure pass-through storefront delegates it to that
agent. Apostra does not run local intake and then forward the same request, or
broadcast it to several possible account authorities.

Before an external mutation, the storefront persists a non-authorizing authority
reservation. Existing grants or seller-owned intakes keep retries on their original
local read-back path even if storefront topology changes.

Delegated decisions are stored locally as an observed-state mirror so buyers can
read pending, accepted, and rejected status consistently. The mirror is not a
second approval: upstream-owned pending requests never appear in the local
seller review queue, and one accepted upstream decision creates at most one
local account authorization.

When an external `sync_accounts` call is asynchronous, the storefront returns a
buyer-pollable task and immediately refreshes that authority with `list_accounts`.
One unambiguous exact account row from the refresh settles the task. Several native
accounts with the same operator, brand, and sandbox remain mapping candidates and do
not decide buyer access. External authorities that
accept asynchronous work must explicitly advertise a reconcilable account roster.
The storefront verifies that capability before forwarding the request, and a
missing or unknown upstream account status never creates access.

If the configured authority is missing, unavailable, or ambiguous, the request
fails before creating access or changing a source mapping. A future account-level
CRM/MCP resolver follows the same rule: it returns exact mapping evidence into the
canonical relationship and source-mapping records; it does not create a parallel
CRM-owned mapping. Existing manual mappings and mappings owned by a different feed
remain protected from overwrite.

## Page views

* **Accounts** shows each complete AccountKey, its verified buyer owner, and the
  seller's decision for that exact account and owner. API rows expose the exact
  `sellerAccountId` separately from the optional legacy `relationshipId`; the
  latter is navigation-only and is never source-account or approval identity.
* **Source coverage** expands the exact seller account across active inventory sources.
  Coverage is `Mapped`, `Not required`, `Not set up`, `Needs account selection`, or `Stale`.
  Source names and native IDs remain seller-private.
* **Sources** shows the last account-listing attempt, last complete snapshot,
  observed/missing counts, and whether Apostra or an upstream sales agent owns the
  account lifecycle. Sellers can refresh a supported source without discarding the
  last complete snapshot when the new listing fails or is incomplete.

The Page is paginated and searchable. It does not expose private source topology
or source-native account IDs to buyers.

The buyer total is storefront-wide: it counts distinct verified buyer
organisations represented by currently eligible exact accounts and does not
change with search, relationship filters, or pagination. A rejected seller
decision does not erase the verified owner, so the account remains in that
ownership total. Revoked or stale buyer lifecycle records are excluded from both
the total and coverage summary.

## Account setup in Advertisers

To see buyers, open the seller **Advertisers** tab: each buyer is an External
advertiser row, and the **Needs you** filter shows rows awaiting your setup
decision. The tab carries the same account-setup status on External roster rows
with an unambiguous seller-account relationship
that appears in Buyer Account Mapping. Each row also carries one of three
classes — House, Self-serve, External — matching the House/Partner-managed/
Self-serve lens exactly: External is any counterparty reached through an AdCP
account relationship (whether that relationship is Apostra-managed or
runs elsewhere; a cross-organization grant renders with the same External
treatment). The **Needs you** filter isolates every row across lenses with an
open case awaiting your decision — there is no separate inbound-requests inbox;
a pending buyer is a roster row like any other.

An External row opens **Media buys** by default, scoped to that exact seller
relationship: the buyer's activity with the seller — its approval work and
active buys, plus synced creative state. It never shows the buyer's own
campaigns. Delivery figures remain in the seller's Media buys and Reporting
views.
Its **Account** tab opens the same
relationship's account-setup case drawer available from Buyer Account Mapping.
The landing gate is class-only: never by whether a relationship id is present
and never by account-setup state. A pending case changes only what the Account
drawer opens to. If a relationship has not resolved yet, the row does not fall
back to the buyer's Campaigns container. Seller storefronts retrieve this projection from `GET
/api/v2/organization/advertisers/account-setup`.

* **Needs setup — waiting on you** means the case is blocked on the seller;
  you provide or confirm the required setup details.
* **Waiting on buyer** means a live request for information is with the buyer;
  the buyer needs to respond.
* **Awaiting billing** means the relationship has a grant requiring payment and
  billing readiness is not established; it clears when a valid ready-to-invoice
  assertion for that billing entity reactivates the grant.

These are neutral setup statuses, not storefront-health errors. Rows with a
closed or inapplicable case do not show a setup status. House and Self-serve
advertisers do not carry a buyer account-setup status — a Self-serve row is
still an advertiser this seller operates under its own roster (same landing
and jobs as House), not a relationship with a setup case.

## Money view

Buyer Account Mapping does not derive proposal or spend rollups by joining an
exact account back to the older operator-and-brand relationship. Those values
remain unavailable until they can be attributed through an exact account route.
Use Demand Inbox and Reporting for current commercial activity.

## When an account listing does not complete

Only a complete reading of a source's account roster replaces the last complete
snapshot. An attempt that stops short records a diagnostic and leaves the previous
snapshot in place, so a partial read never archives accounts that still exist.

The diagnostic names **whose** limit stopped the attempt, because the remedy is
different in each case:

* `INCOMPLETE_LISTING` — the source itself answered with a partial roster, or
  reported an error while reading it. Check the ad server or sales agent: a
  permission that no longer covers the whole roster is the usual cause.
* `ROSTER_DRAIN_TIMED_OUT` — Apostra ran out of its own time budget before
  finishing the roster read. Scheduled attempts get a longer budget than a
  refresh you trigger by hand, so this often clears on its own within the next
  polling cycle.
* `ACCOUNT_LISTING_FAILED` — the roster read itself failed. Inspect the inventory
  source connection and its credentials.

Apostra follows pagination to the source's terminal page and does not impose an
account-count ceiling. Large complete rosters are published in database batches.

A source that has never once produced a complete snapshot has no accounts to
map, so no buyer relationship can reach `Mapped` coverage on it — and for a
provider that requires an explicit account, that leaves the source unable to
execute. Apostra alerts on that state rather than retrying silently.

### Select from the full source roster

When a source needs an account, page or search its complete observed roster with
[Search a source account roster](/v2/storefront/account-mappings/tasks/list-source-roster),
then map one authenticated native account to the exact seller account. The Page
does not treat an operator, brand, or sandbox match as approval or as evidence
that a source account belongs to a different complete AccountKey. A dedicated
native account stays owned by that complete AccountKey after its current mapping
is archived, so it cannot later be rebound to another key. **Use Interchange
default** mappings remain intentionally shareable.

## Review pending buyer access

When a buyer requests access to a relationship that requires seller approval,
the request stays pending until a storefront administrator decides it. List the
pending requests with `list_seller_account_grant_reviews` in storefront MCP or
`GET /api/v2/storefront/account-mappings/reviews` in the storefront REST API.
Each row includes the current `version` needed to prevent a decision against
stale review state, the snapshotted policy result, CRM-match status, and the
canonical `intakeId`. The released `grantId` field remains as a deprecated alias
for compatibility; a pending review is not an authorization grant.

Seller relationship rows expose each pending request's resolution authority,
requested billing path, `billingReady`, and truthful `allowedActions`. Direct
operator or advertiser billing cannot be accepted until its billing entity is
resolved; `link_existing` remains available to supply that verified entity.

Use `decide_seller_account_grant_review` or
`POST /api/v2/storefront/account-mappings/reviews/{grantId}/decision` with
`decision: "accept"` to accept using the billing path already resolved for the
request. The released `approve_interchange` value remains a compatibility alias
for agent billing. `link_existing` is the legacy direct-billing acceptance path:
it requires an operator or advertiser billing entity, but it does not create a
CRM link or inventory-source mapping. Rejections require a reason.

A buyer's request can name the payment terms it wants, such as `net_60`
(once requesting terms launches for all buyers). The review shows
them, and accepting the request accepts those terms: the account
then reports them in `payment_terms`. There is no counter-offer. If the terms
don't work for you, reject the request and say why. Your intake policy can
approve a request automatically only when it asks for the `net_60` default or
names no terms; any other terms always wait for your review. While a request is
pending, the buyer can send different terms, which replace the earlier ones.
Once you have decided, the decision and its terms stand; a later request for
different terms is refused on that account and changes nothing.

When a buyer must choose payment terms before an agent-billed account can open,
that is a buyer setup step rather than a seller failure. Discovery continues
without opening the account only when the seller explicitly declares that an
account is not required: that seller receives a public discovery request. A
seller that requires an account, or does not declare whether it requires one,
serves its warmed public catalogue when available. Otherwise the buyer sees the
`payment_terms` Buyer Setup step. Choosing terms makes the held
account-provisioning work for the billing organization and its current direct
children eligible to retry immediately; no seller action is needed. The
activation worker also performs an hourly, best-effort recheck for a buyer
reparented after that save. A processing backlog can delay that convergence.

Acceptance creates buyer access. Native account creation and source mapping are
separate operations, and existing mappings keep their state unless an
administrator explicitly changes them.

After access is approved, decide coverage separately for every source the account
may use. The Source coverage view is the seller's readback of those decisions; it
does not edit them in this release. An authenticated seller integration can map an
authenticated source-native account or confirm `Not required` when that source's
contract is intentionally unscoped. The REST operation is
`POST /api/v2/storefront/account-mappings/accounts/{accountId}/sources/{inventorySourceKey}/decision`.
Use `expectedVersion: 0` for the first decision and the currently displayed coverage
version for a replacement. A stale version is rejected instead of silently changing
the source used for products or buys.

For example, a modular source that does not consume a native advertiser account is
made eligible explicitly—not inferred from its execution type:

```json theme={null}
{
  "expectedVersion": 0,
  "decision": "not_required"
}
```

### Use Apostra default

For an ad-server-backed source, the account picker can offer **Use Apostra
default** instead of mapping a dedicated account: it maps the relationship to
your shared default advertiser on that connected ad server, rather than
creating or choosing an advertiser for this buyer alone.

This option is offered only when every active grant on the relationship
settles through **agent** (consolidated) billing and the source's
configured default advertiser currently reads back healthy. Direct-billed
(operator or advertiser) relationships never see it — a direct-billed buyer
needs its own advertiser so invoicing and reporting resolve to that buyer, not
the shared default. Read `GET
/api/v2/storefront/account-mappings/accounts/{accountId}/sources/{inventorySourceKey}/interchange-default-eligibility`
before offering the choice; an ineligible response carries a machine-readable
reason and never a raw boolean.

Choosing it records the mapping through the same decision endpoint as a
dedicated account, with `bindingMode: "shared_default"` and no
`sourceExternalAccountId` — Apostra resolves the native account
server-side, so this option never exposes the shared advertiser's native ID.

Apostra keeps the mapping healthy going forward. If the ad server's
configured default advertiser later changes, or the ad server stops reporting
it, the mapping is marked stale and execution pauses on it until it is either
reconciled against the new default or you choose a dedicated account instead
— it never silently keeps executing against the old default or falls back to
one automatically. A dedicated mapping is unaffected by a default-advertiser
change elsewhere on the source.

## CSV exports and imports

The Page can download:

* an empty `source_account_bindings.csv` template for the active mapping mode;
* current healthy source mappings; and
* active native accounts with their source namespace, generation,
  status, and listing version.

In complete AccountKey mode, the versioned mapping columns are:

```text theme={null}
schema_version,operation,operator_domain,operator_unit_id,brand_domain,brand_id,brand_countries,currency,timezone,sandbox,inventory_source_key,binding_mode,source_external_account_id
```

Every v2 row explicitly declares `binding_mode` (`dedicated` or
`shared_default`). Exports protect formula-leading opaque identifiers with a
reversible escape; importing the v2 export restores the exact identifier.
`shared_default` rows may be shared by multiple complete AccountKeys and never
claim dedicated ownership. A row cannot silently change a matching dedicated
mapping into a shared default (or the reverse); use the explicit source-account
transition. Legacy v1 files are rejected in complete-key mode, and a legacy
relationship-level shared default must be upgraded to an exact AccountKey or
removed before a complete-key export.

Select **Import feed** from the Page to open the portable import Task. The Task:

1. lets an administrator choose the inventory sources covered by the file;
2. uploads the bytes directly to private, short-lived storage;
3. validates the exact schema, hashes, row count, relationships, source accounts,
   and current mapping authority;
4. shows creates, updates, archives, unchanged rows, and quarantined rows; and
5. applies the reviewed set in one atomic, version-checked commit.

Sandbox relationships use the same reviewed mapping flow as live relationships.
If a storefront has both a sandbox and live relationship with the same operator
and brand domains, the Task quarantines that row instead of guessing which one
to map.

Each successful commit records the administrator, revision, and impact in the
seller's activity audit. Audit delivery is durable and does not make the mapping
transaction depend on a second service being available at commit time.

Snapshot imports treat the selected sources as complete. A missing row can archive
only a mapping that an earlier revision of the same feed created; manual mappings and
mappings owned by another feed are never removed. Any quarantined snapshot row blocks
the commit. Delta imports require the last committed revision ID and may apply only
accepted rows after the administrator reviews the quarantine impact.

<Warning>
  This release imports only `source_account_bindings.csv`. It does not create
  CRM records, canonical operator-and-brand relationships, grants, or native
  accounts. Exported native-account choices must already come from an
  authenticated inventory source. Files are limited to 10 MB and 10,000 data
  rows.
</Warning>

The MCP Task launcher is:

```json theme={null}
{
  "name": "import_seller_account_feed",
  "arguments": {
    "coveredInventorySourceKeys": ["gam-primary"]
  }
}
```

The upload, preview, and commit capabilities are app-only; they do not appear in the
model's tool catalog.

## CRM and commercial policy

A CRM is optional evidence and workflow acceleration. Runtime product discovery,
execution, and reporting use the inventory-source mapping for the relevant leg.
Credit limits, billing approvals, and permissions remain in their owning typed
commercial contracts; the account-mapping export does not copy or interpret
arbitrary CRM fields.

Native mapping support is runtime-specific. Third-party agent-backed sources and managed
Google Ad Manager or FreeWheel sources consume explicit native-account mappings.
Sellers can refresh those sources' authenticated advertiser choices before exporting
or importing mappings. Third-party `list_accounts` results retain the upstream
operator, brand, status, and freshness needed for diagnosis, but Apostra does not
offer upstream approval or creation actions. A partial, failed, duplicate, or
non-advancing refresh keeps the previous complete choices active and never archives
an omitted advertiser. Automatic polling includes managed sources and external
agents that explicitly advertise `list_accounts`. Account-capable modular sources
can be refreshed on demand; capability-aware periodic modular scheduling remains a
follow-on so unsupported compositions are not retried forever. Modular sources
can also consume mappings when their active modules declare one shared account
namespace across products, media buys, delivery, and account resources. CitrusAd
is the first supported composition and maps a supplier team. The Page labels an
incomplete composition as unsupported; it may participate only through an
explicit, contract-valid `Not required` decision where account scope is not
needed.

## Asking the buyer for more information

Some intakes need something from the buyer before you can decide them — a
completed W-9, a signed contract, an answer to a credit question. Rather than
guessing or rejecting outright, request it: the buyer's account stays
`pending_approval`, now carrying a message and a link into your own process
(a form, a DocuSign envelope, a portal). The buyer's agent presents the
message as untrusted text and offers the link to an authorized human — it
never treats the message as instructions, and it never opens the link
automatically.

Opening the link is not completion. You confirm explicitly once the material
actually arrives, and only then does the case return to your queue ready for
a decision.

If you no longer need what you asked for, withdraw the request instead of
declining the whole case — the case stays open and returns to your queue,
the same way an expired request re-blocks on you.

<CardGroup cols={2}>
  <Card title="Request buyer information" href="/v2/storefront/buyer-account-mapping/tasks/request-buyer-information" icon="circle-question">
    Ask for what you need, with an expiration
  </Card>

  <Card title="Confirm buyer information" href="/v2/storefront/buyer-account-mapping/tasks/confirm-buyer-information" icon="circle-check">
    Record that it arrived
  </Card>

  <Card title="Withdraw an information request" href="/v2/storefront/buyer-account-mapping/tasks/withdraw-buyer-information-request" icon="circle-minus">
    Drop the ask without deciding the case
  </Card>
</CardGroup>

## Billing readiness for direct-billed accounts

Accepting or linking a buyer decides admission — whether they get in. For
**operator** or **advertiser** billing, that is a separate question from
whether you can actually invoice them: your finance system (CRM, ERP, a staff
member, or an external workflow) has to explicitly confirm the buyer is
billable before their account can place direct-billed media buys. Merely
creating a CRM account or a native advertiser is never itself that
confirmation. **Agent** billing (Apostra settlement) never needs this —
Apostra handles collection, not you.

An operator/advertiser-billed account you've accepted or linked but not yet
confirmed billable stays `pending_approval` — no account is created until
readiness exists. Your decision is remembered; asserting readiness completes
it immediately, activating the account without you having to decide again.
Revoking readiness on an account that is already `active` fails closed: it
moves the account to `payment_required`, immediately blocking new
direct-billed activity without touching buys already placed, and it never
silently falls back to agent/Apostra billing on your behalf.

The review queue's `billingGate` field on each pending request shows whether
this gate applies and where it stands: `not_required` (agent billing),
`pending` (never asserted), `ready` (an active assertion exists), or `revoked`
(one existed and was withdrawn). When the gate is `ready` or `revoked`,
`billingGate.assertionId` names the assertion, so you can call the revoke
endpoint below even without keeping the original assert response.

<CardGroup cols={2}>
  <Card title="Assert billing readiness" href="/v2/storefront/buyer-account-mapping/tasks/ready-to-invoice" icon="file-invoice-dollar">
    Confirm a direct-billed buyer is billable, or revoke that confirmation
  </Card>
</CardGroup>


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