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

# Accounts and agents

> AdCP accounts and agents: the four entities in every transaction (brand, account, operator, agent), account-id namespaces, buyer-declared accounts, and billing configuration.

AdCP distinguishes four entities in every billable operation:

| Entity       | Question                            | How identified                                                                                  |
| ------------ | ----------------------------------- | ----------------------------------------------------------------------------------------------- |
| **Brand**    | Whose products are advertised?      | Brand reference: `domain` + optional `brand_id` ([brand.json](/docs/brand-protocol/brand-json)) |
| **Account**  | Who gets billed? What rates apply?  | [Account reference](#account-references)                                                        |
| **Operator** | Who operates on the brand's behalf? | Domain (e.g., `pinnacle-media.com`)                                                             |
| **Agent**    | What software is placing the buy?   | Authenticated session                                                                           |

**Brand** — The advertiser whose products or services are promoted. Identified by a `brand` reference (`domain` + optional `brand_id`), resolved via `/.well-known/brand.json`. Single-brand houses use the domain alone (no `brand_id`).

**Account** — A billing relationship between a buyer and seller. Determines rate card, payment terms, credit limit, and who receives invoices. Every billable operation requires an account reference — a seller-assigned `account_id` when the seller or upstream platform owns the canonical account namespace, or a natural key (`brand`, `operator`) when that tuple is the durable protocol key for buyer-declared accounts. Sandbox accounts follow the same model — account-id namespaces use pre-existing sandbox IDs from `list_accounts` or out-of-band setup, while buyer-declared sandboxes use the natural key with `sandbox: true`.

**Operator** — The entity driving buys — an agency trading desk, the brand's internal team, or another entity acting on behalf of the advertiser. Identified by domain and verifiable via [authorized operators](#authorized-operators) in `brand.json`.

**Agent** — The software placing buys and managing campaigns. Authenticates with the seller and may operate on behalf of multiple operators and brands.

See [Accounts Protocol overview](/docs/accounts/overview) for the full commercial model and [sync\_accounts](/docs/accounts/tasks/sync_accounts) for the task reference.

## What sellers declare

Sellers configure the `account` section of [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities#account):

**1. Which billing models do you support?** (`supported_billing`)

The buyer must pass one of these values as `billing` in every `sync_accounts` entry. The seller either accepts or rejects.

| Billing      | Who is invoiced                          | Use case                                                                                          |
| ------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `operator`   | Operator (agency or brand buying direct) | Operator buying on their own terms                                                                |
| `agent`      | Agent                                    | Agent consolidates billing across brands                                                          |
| `advertiser` | Advertiser directly                      | Operator places orders but advertiser pays (common on social platforms and in DACH B2B workflows) |

**2. Do you require operator-level auth?** (`require_operator_auth`)

This field determines the authentication model and the account reference shape:

When `false` (default) — **buyer-declared accounts**: the seller trusts the agent. The agent authenticates once and declares accounts via `sync_accounts`. On subsequent requests, the buyer passes the natural key (`brand` + `operator`) and the seller resolves internally.

When `true` — **account-id namespaces**: each operator must authenticate with the seller directly. The agent obtains a credential per operator — via OAuth using the seller's `authorization_endpoint`, or via API key out-of-band. Subsequent requests pass a seller-assigned `account_id`. If a credential may access more than one account, the seller MUST expose `list_accounts` and the buyer MUST resolve an explicit account before the first account-scoped request. If a credential is bound to exactly one account, the seller SHOULD expose `list_accounts` returning that singleton; a seller MAY omit `list_accounts` only when it supplies the same explicit account ID through another declared path or out-of-band onboarding.

For sandbox, the path follows the account namespace: account-id namespaces use pre-existing test accounts from `list_accounts` or out-of-band setup; buyer-declared accounts use `sync_accounts` with `sandbox: true` and reference by natural key.

Sellers can also declare `account_financials: true` to expose account-level financial data (spend, credit, invoices) via [`get_account_financials`](/docs/accounts/tasks/get_account_financials). This only applies to operator-billed accounts.

**Example capabilities:**

```json theme={null}
{
  "account": {
    "require_operator_auth": false,
    "supported_billing": ["operator", "agent"]
  }
}
```

Sellers that support `advertiser` billing declare it explicitly:

```json theme={null}
{
  "account": {
    "require_operator_auth": false,
    "supported_billing": ["operator", "agent", "advertiser"]
  }
}
```

These fields combine into common patterns.

## Seller patterns

Which kind of platform are you buying from? That determines the account setup pattern.

| Platform type                              | Account pattern                       | `require_operator_auth` | `supported_billing`                       |
| ------------------------------------------ | ------------------------------------- | ----------------------- | ----------------------------------------- |
| [Social / walled garden](#social-platform) | Upstream-managed account-id namespace | `true`                  | `["operator"]`                            |
| [Direct publisher](#direct-publisher)      | Buyer-declared accounts               | `false`                 | `["operator"]` or `["operator", "agent"]` |
| [DSP / programmatic](#dsp--programmatic)   | Buyer-declared accounts               | `false`                 | `["agent"]`                               |

### Social platform

The operator already has an account on the platform — an ad account, a business manager, a self-serve dashboard. The upstream platform owns the canonical account namespace accessible to that credential. The agent obtains the operator's credentials (via OAuth or API key), opens a per-operator session, resolves an explicit account through `list_accounts`, and uses the returned `account_id` values. The platform bills the operator directly.

**Capabilities:**

```json theme={null}
{
  "account": {
    "require_operator_auth": true,
    "supported_billing": ["operator"],
    "authorization_endpoint": "https://seller.example.com/oauth/authorize"
  }
}
```

**Buyer workflow:**

1. Call `get_adcp_capabilities` — see `require_operator_auth: true` and `authorization_endpoint`
2. For each operator:
   a. Obtain operator's credential (OAuth via `authorization_endpoint`, or API key out-of-band)
   b. Open a new session with the operator's credential
   c. Call `list_accounts` to discover accounts visible to that credential
3. Human or policy selects the correct account from the list
4. Call `get_products` / `create_media_buy` with the operator's session and `{ "account_id": "..." }`

**list\_accounts response:**

```json theme={null}
{
  "accounts": [{
    "account_id": "acc_spark_social_001",
    "name": "Spark paid social",
    "brand": { "domain": "nova-brands.com", "brand_id": "spark" },
    "operator": "pinnacle-media.com",
    "status": "active",
    "billing": "operator",
    "account_scope": "operator_brand"
  }]
}
```

Subsequent calls use the discovered ID:

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

**Key point:** The operator's credential — not the agent's — authorizes all calls in that session. The buyer does not declare or create accounts through AdCP in the 3.0.x account-id model; `list_accounts` mirrors the upstream namespace. If the seller exposes `sync_accounts`, it is only for settings updates against an existing `account_id`, not natural-key provisioning, unless a future explicit capability declares account-id provisioning.

### Direct publisher

The publisher trusts the agent but bills the operator directly. The agent sets up accounts via `sync_accounts` — no per-operator login needed. Accounts may require human approval (credit checks, legal agreements) before becoming active.

Many publishers also accept agent billing (`supported_billing: ["operator", "agent"]`). The buyer chooses per account — operators with a direct relationship use `billing: "operator"`, everything else uses `billing: "agent"`. If the seller doesn't support the requested billing for a particular account, it rejects the request and the agent re-submits with a different model.

**Capabilities:**

```json theme={null}
{
  "account": {
    "supported_billing": ["operator", "agent"]
  }
}
```

**Buyer workflow:**

1. Call `get_adcp_capabilities` — see `require_operator_auth` absent (defaults to `false`)
2. Call `sync_accounts` for each brand/operator pair
3. Wait for account status `active` — may require human to complete credit/legal at `setup.url`
4. Call `get_products` with `account` reference
5. Call `create_media_buy` with `account` reference

**sync\_accounts request — brand buying direct:**

```json theme={null}
{
  "accounts": [{
    "brand": { "domain": "acme-corp.com" },
    "operator": "acme-corp.com",
    "billing": "operator"
  }]
}
```

Seller acknowledges the request but requires setup before provisioning:

```json theme={null}
{
  "accounts": [{
    "brand": { "domain": "acme-corp.com" },
    "operator": "acme-corp.com",
    "action": "created",
    "status": "pending_approval",
    "billing": "operator",
    "account_scope": "brand",
    "setup": {
      "url": "https://seller.example.com/advertiser-onboard",
      "message": "Complete advertiser registration and credit application"
    }
  }]
}
```

The seller has acknowledged the relationship `(brand: "acme-corp.com", operator: "acme-corp.com", billing: "operator")`, but the account is pending review before it becomes active. A human at Acme Corp completes the setup at the URL. To check progress, the agent either:

* Re-calls `sync_accounts` with the same natural key — the seller returns the updated status
* Receives a webhook notification if `push_notification_config` was provided in the request

**Key point:** `pending_approval` is the normal path. Every buyer needs a direct relationship with the seller.

**Billing rejection — operator billing not available:**

The seller supports operator billing in general, but may not support it for every operator. Here, the agent requests operator billing for an operator without a direct relationship:

```json theme={null}
{
  "accounts": [{
    "brand": { "domain": "acme-corp.com" },
    "operator": "acme-corp.com",
    "billing": "operator"
  }]
}
```

Seller rejects the request because this operator has no direct billing relationship:

```json theme={null}
{
  "accounts": [{
    "brand": { "domain": "acme-corp.com" },
    "operator": "acme-corp.com",
    "action": "failed",
    "status": "rejected",
    "errors": [{
      "code": "BILLING_NOT_SUPPORTED",
      "message": "Operator billing is not available for this account. Re-submit with billing: \"agent\"."
    }]
  }]
}
```

The agent re-submits with `billing: "agent"` or informs the buyer that operator billing is not available with this seller. Billing is never silently remapped.

### DSP / programmatic

All billing flows through the agent. The agent has a standing relationship with the platform and consolidates billing across all brands and operators. Accounts are created instantly — no human approval needed.

**Capabilities:**

```json theme={null}
{
  "account": {
    "supported_billing": ["agent"]
  }
}
```

**Buyer workflow:**

1. Call `get_adcp_capabilities` — see `supported_billing: ["agent"]`
2. Call `sync_accounts` for each brand/operator pair with `billing: "agent"`
3. Accounts are active immediately — no human approval needed
4. Call `get_products` / `create_media_buy` with `account` reference

**sync\_accounts request:**

```json theme={null}
{
  "accounts": [{
    "brand": { "domain": "nova-brands.com", "brand_id": "spark" },
    "operator": "pinnacle-media.com",
    "billing": "agent"
  }]
}
```

Account active immediately:

```json theme={null}
{
  "accounts": [{
    "brand": { "domain": "nova-brands.com", "brand_id": "spark" },
    "operator": "pinnacle-media.com",
    "action": "created",
    "status": "active",
    "billing": "agent",
    "account_scope": "operator_brand"
  }]
}
```

**Key point:** The agent receives a single consolidated invoice. Per-brand accounts give reporting granularity but billing is centralized.

## Authorized operators

Brands declare who can represent them in `/.well-known/brand.json` via the `authorized_operators` field. Sellers SHOULD verify operators against this when processing `sync_accounts`.

```json theme={null}
{
  "house": {
    "domain": "nova-brands.com",
    "name": "Nova Brands"
  },
  "brands": [
    { "id": "spark", "names": [{"en": "Spark"}] },
    { "id": "glow", "names": [{"en": "Glow"}] }
  ],
  "authorized_operators": [
    {
      "domain": "pinnacle-media.com",
      "brands": ["spark", "glow"],
      "countries": ["US", "GB", "DE"]
    },
    {
      "domain": "summit-agency.jp",
      "brands": ["spark"],
      "countries": ["JP"]
    },
    {
      "domain": "nova-brands.com",
      "brands": ["*"]
    }
  ]
}
```

| Field       | Required | Description                                                      |
| ----------- | -------- | ---------------------------------------------------------------- |
| `domain`    | Yes      | Operator's domain                                                |
| `brands`    | Yes      | Brand IDs this operator can represent. `["*"]` means all brands. |
| `countries` | No       | ISO 3166-1 alpha-2 country codes. Omit for global authorization. |

### Verification flow

1. Resolve `{brand.domain}/.well-known/brand.json`
2. Check `authorized_operators` for matching `domain` with the brand in `brands`
3. If found → proceed (account may still need credit/legal approval)
4. If not found → reject the account (`action: "failed"`) or return `pending_approval` for manual review

Verification is a trust signal, not a gate. Finding the operator in `brand.json` lets the seller fast-track provisioning. If the operator isn't listed, the seller can still approve through its own review process.

**Self-authorization is implicit.** When the `operator` domain matches the brand's domain, the brand is operating directly — no listing in `authorized_operators` is needed.

`authorized_operators` models the interface between the brand and whoever operates on its behalf. It does not model internal agency hierarchies.

## Buyer-agent identity

`authorized_operators` tells the seller whether an operator is allowed to represent a brand. It doesn't tell the seller who the *agent* placing the call is, or what commercial relationship is on file with that agent. Those are different questions, and the seller checks both before provisioning.

Two layers run on every `sync_accounts` request:

| Layer                            | Question                                                              | Where it lives                                                                                                                                                                                                                                                                                                                      |
| -------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Agent identity**               | Which buyer agent issued this request?                                | The seller's onboarding record, looked up by signed-request `agent_url` (when [request signing](/docs/building/by-layer/L1/security#signed-requests-transport-layer) is in use) or by the bearer / API-key / OAuth credential the agent presented. Signature or credential establishes identity; authorization is a separate check. |
| **Brand-operator authorization** | Is the operator named in the request authorized to act for the brand? | `brand.json` `authorized_operators` (above). Verified whether the request is signed or not.                                                                                                                                                                                                                                         |

Both layers MUST pass. A signed request from an onboarded agent for an unauthorized operator gets rejected on the brand-operator check; a request from an unrecognized agent for an authorized operator gets rejected on the identity check. Sellers that advertise [`request_signing.required_for`](/docs/building/by-layer/L1/security#transport-scope) on `sync_accounts` reject unsigned traffic at the identity layer; sellers that don't advertise it MAY still require an established credential mapping before agent-billable values are accepted.

The brand-operator check runs against the seller's cached `brand.json` per [Operator revocation and caching](#operator-revocation-and-caching) — revocation is eventual. Sellers performing high-value or first-time-on-this-brand provisioning SHOULD bypass the cache to close the TOCTOU window.

**SDK naming for the brand-operator authorization Protocol.** SDKs that surface a typed Protocol for the brand-operator check (for adopters to plug their own resolver into) SHOULD name it after the file consulted: `BrandAuthorizationResolver` (or equivalent in idiomatic casing). The file is `brand.json/authorized_operators` — the brand-side declaration of who may represent the brand. SDKs SHOULD NOT name this Protocol after `adagents.json`, which is publisher-side / data-provider-side and models a different relationship (which sales agents may sell that publisher's inventory). Naming the buyer-side resolver `AdagentsResolver` confuses the two surfaces and locks adopters into the wrong mental model. This is a spec-side recommendation; SDK conventions track upstream.

**The agent's commercial state is offline.** Whether a buyer agent is *passthrough-only* (no payments relationship — only the operator can be invoiced) or *agent-billable* (the agent can be invoiced directly) is recorded in the seller's onboarding system, the same way operator account creation is. Provisioning that record — contract, KYC, payment terms, billing entity capture — is out of scope for AdCP. What's in scope is two on-wire consequences:

1. **Runtime billing gate.** A passthrough-only agent that submits `billing: "agent"` or `billing: "advertiser"` is rejected with `BILLING_NOT_PERMITTED_FOR_AGENT` and an `error.details.suggested_billing` of `operator`. See [Billing and Account Setup](/docs/building/by-layer/L3/error-handling#billing-and-account-setup) for the recovery contract.
2. **Per-agent defaults.** Sellers MAY pre-fill `payment_terms`, `billing_entity`, rate-card linkage, and credit limit from the buyer agent's onboarding record when provisioning new accounts under that agent. Per-account values on the `sync_accounts` request always take precedence over per-agent defaults — the buyer can override per row. The per-agent layer is a recommended implementation pattern (it mirrors how SSPs maintain `buyer_id` / `seat_id` rows for OpenRTB DSPs); smaller publishers MAY collapse to seller-wide defaults until they have receivables ops that distinguish per-agent terms.

## Account references

Every account-scoped operation accepts an `account` object instead of a flat `account_id` string. The seller's `require_operator_auth` capability determines the auth model and reference shape; tool exposure distinguishes upstream-managed `account_id` namespaces from seller-defined IDs supplied out-of-band.

<Note>
  Sellers that support caller-scope introspection attach an optional `authorization` object to each per-account entry in [`sync_accounts`](/docs/accounts/tasks/sync_accounts) and [`list_accounts`](/docs/accounts/tasks/list_accounts) responses — listing the tasks and request fields this caller is allowed to use on the account, plus any standard named scope (e.g., `attestation_verifier`). See [Caller authorization](/docs/accounts/overview#caller-authorization) for the full shape and semantics.
</Note>

### Account-id namespaces (`require_operator_auth: true`)

Accounts are managed outside of AdCP. The advertiser creates an account on the seller's platform, grants the operator permission to manage it, and the buyer passes a seller-assigned `account_id`. The agent is not involved in account creation or billing setup — those are handled between the advertiser, operator, and seller directly.

**Typical sellers:** Social platforms, self-serve ad platforms — anywhere the advertiser already has an account.

**Upstream-managed workflow:**

1. Advertiser creates an account on the seller's platform (out-of-band)
2. Advertiser grants the operator permission to manage the account (out-of-band)
3. Agent calls `list_accounts` to discover available accounts
4. Human selects the correct account from the list
5. Agent passes `{ "account_id": "acc_acme_001" }` on every request (`get_products`, `create_media_buy`, etc.)

`list_accounts` is mandatory when the authenticated credential may access more than one account because the upstream owns the namespace. When the credential is bound to exactly one account, sellers SHOULD still expose `list_accounts` returning that singleton so SDKs can auto-select it and send explicit `{ "account_id": "..." }` on required-account calls. `sync_accounts` provisioning is out of scope for account-id namespaces in 3.0.x unless a future explicit capability declares it; if `sync_accounts` is exposed today, it is settings-update mode for an existing `account_id`.

**Seller-defined workflow:**

Some sellers use `account_id` without exposing an account discovery surface. In that pattern, the seller gives the buyer an account ID during onboarding or configuration, and the buyer passes that ID on account-scoped calls. Absence of `list_accounts` means there is no protocol namespace to discover; it does not mean the buyer should try to provision by natural key.

### Buyer-declared accounts (`require_operator_auth: false`)

The agent manages the buying relationship. It calls `sync_accounts` to tell the seller who's advertising, who's operating on the brand's behalf, and who's paying. The seller provisions accounts and responds with status — the account IDs are a byproduct of the declaration, not something the buyer needs to know upfront.

**Typical sellers:** Traditional publishers, retail media networks, DSPs — anywhere the buying relationship is established programmatically.

`sync_accounts` is the declaration tool. Each entry is a set of flags that tells the seller what the buyer needs:

| Flag                                     | What it tells the seller                                                                                                                                                                                                            |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `brand` (`domain` + optional `brand_id`) | Which brand is advertising                                                                                                                                                                                                          |
| `operator`                               | Who operates on the brand's behalf (agency, trading desk, or the brand itself)                                                                                                                                                      |
| `billing`                                | Who gets the invoice — `operator`, `agent`, or `advertiser`                                                                                                                                                                         |
| `billing_entity`                         | Structured business entity details for the party responsible for payment — legal name, VAT ID, tax ID, address, contacts, and bank details. Used for formal B2B invoicing. Bank details are write-only (never echoed in responses). |
| `payment_terms`                          | Payment terms for this account (`net_15`, `net_30`, `net_45`, `net_60`, `net_90`, `prepay`). The seller must accept these terms or reject the account — terms are never silently remapped.                                          |
| `sandbox`                                | Whether this is a sandbox (test) account — no real spend. Only used with buyer-declared accounts; account-id namespace sandboxes are pre-existing and discovered through `list_accounts` or supplied out-of-band.                   |

Every combination of flags that might require the seller to do something different — bill a different entity, set up a different rate card, create a sandbox — is a distinct declaration.

### Billing entity and invoice recipient

For markets that require structured invoicing data (e.g., EU B2B transactions requiring VAT IDs), the `billing_entity` on an account provides the default business entity details for whoever `billing` points to. This includes legal name, tax identifiers, postal address, billing contact, and bank details.

On individual media buys, an `invoice_recipient` can override the account default — useful when a specific campaign should be billed to a different party. When `invoice_recipient` differs from the account default and the account has `governance_agents`, the seller MUST include it in the `check_governance` request so the governance agent can approve or reject the billing redirect.

**Workflow:**

1. Agent calls `sync_accounts` with one or more declarations
2. Seller provisions or links accounts for each, responds with status:
   * `active` — ready to use
   * `pending_approval` — seller reviewing (human may need to visit `setup.url`)
   * `rejected` — seller declined the request
3. For subsequent requests, pass the account reference:
   * **Buyer-declared accounts** (`require_operator_auth: false`): pass the natural key `{ "brand": { "domain": "acme-corp.com" }, "operator": "pinnacle-media.com" }`
   * **Account-id namespaces** (`require_operator_auth: true`): pass `{ "account_id": "acc_acme_001" }` (discover via `list_accounts` for upstream-managed namespaces, or receive out-of-band for seller-defined namespaces)
   * **Sandbox (buyer-declared)**: pass the natural key with `sandbox: true` (declared via `sync_accounts`)
   * **Sandbox (account-id namespace)**: pass `{ "account_id": "test_acc_001" }` (pre-existing test account, discovered via `list_accounts` or supplied out-of-band)
4. When anything changes (billing model, new brand, new operator), call `sync_accounts` again

The agent may be directly responsible for billing when `billing` is `"agent"`. When `billing` is `"operator"` or `"advertiser"`, the agent facilitates but is not the invoiced party. The seller may require human approval before activating accounts.

### Natural key semantics

The tuple `(brand, operator, sandbox)` uniquely identifies an account relationship. The `brand` is a nested object with `domain` and optional `brand_id`. `operator` is always required — when the brand operates directly, set `operator` to the brand's domain. `sandbox` defaults to `false` when omitted. For example, `{brand: {domain: "acme-corp.com"}, operator: "acme-corp.com"}` (brand buying direct) is a different account from `{brand: {domain: "acme-corp.com"}, operator: "pinnacle-media.com"}` (brand via agency). Adding `sandbox: true` references the sandbox account for the same pair.

See [sync\_accounts task reference](/docs/accounts/tasks/sync_accounts) for the full request/response schema.

### Account status

| Status             | Meaning                     | Next step                                                              |
| ------------------ | --------------------------- | ---------------------------------------------------------------------- |
| `active`           | Ready to use                | Place buys on this account                                             |
| `pending_approval` | Seller reviewing            | Human may need to visit `setup.url`. Poll `list_accounts` for updates. |
| `rejected`         | Seller declined the request | Review rejection reason, adjust and re-sync, or contact seller         |
| `payment_required` | Credit limit reached        | Add funds or route spend to other accounts                             |
| `suspended`        | Was active, now paused      | Contact seller                                                         |
| `closed`           | Was active, now terminated  | —                                                                      |

### Account scope

The agent requests accounts by natural key — `(brand, operator)`. The seller decides what granularity to assign. The `account_scope` field in the response tells the agent how the seller resolved the request:

| Scope            | Meaning                                                        | Example                                                                                                        |
| ---------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `operator`       | One account for all brands under this operator                 | Agent sends (Pinnacle Media, Acme) and (Pinnacle Media, Nova) — seller maps both to the Pinnacle Media account |
| `brand`          | One account for this brand regardless of operator              | Agent sends (Acme, Pinnacle Media) and (Acme, Summit Agency) — seller maps both to the Acme account            |
| `operator_brand` | Dedicated account for this operator+brand pair                 | Agent sends (Pinnacle Media, Acme) — seller creates a specific Acme-via-Pinnacle account                       |
| `agent`          | Agent-scoped account with no brand- or operator-specific split | Agent sends any brand — seller maps the request to the standing agent-scoped account                           |

The agent does not choose the scope — the seller assigns it based on its own account policy. An agent requesting `(brand: {domain: "acme-corp.com"}, operator: "pinnacle-media.com")` might receive an operator-scoped account, a brand-scoped account, or a dedicated operator\_brand account depending on the seller.

When multiple natural keys resolve to the same scope, the `account_scope` explains why.

For buyer-declared accounts (`require_operator_auth: false`), use natural keys (`brand` + `operator`) on subsequent requests — adding `sandbox: true` for sandbox accounts. A seller may also return an `account_id` from `sync_accounts` as its internal handle, but the seller MUST continue accepting the natural-key `AccountRef` for every account provisioned this way. For account-id namespaces (`require_operator_auth: true`), discover account IDs via `list_accounts` for upstream-managed namespaces, or receive them out-of-band for seller-defined namespaces — including sandbox test accounts.

## Error codes

| Code                     | When returned                                    | Resolution                                      |
| ------------------------ | ------------------------------------------------ | ----------------------------------------------- |
| `ACCOUNT_REQUIRED`       | Multiple accounts; seller can't determine which  | Pass `account_id` in the account reference      |
| `ACCOUNT_NOT_FOUND`      | `account_id` doesn't exist or agent lacks access | Check account reference, re-run `sync_accounts` |
| `ACCOUNT_SETUP_REQUIRED` | Natural key resolved but account needs setup     | Check `details.setup` for URL/message           |
| `ACCOUNT_AMBIGUOUS`      | Natural key resolves to multiple accounts        | Pass `account_id` or more specific natural key  |
| `PAYMENT_REQUIRED`       | Credit limit reached or funds depleted           | Add funds, route to another account             |
| `ACCOUNT_SUSPENDED`      | Account not in good standing                     | Contact seller                                  |
| `BRAND_REQUIRED`         | Billable operation without brand reference       | Include `brand` in request                      |

When the seller returns `ACCOUNT_REQUIRED`, it includes the available accounts:

```json theme={null}
{
  "errors": [{
    "code": "ACCOUNT_REQUIRED",
    "message": "Multiple accounts available. Please specify account_id in the account reference.",
    "details": {
      "available_accounts": [
        { "account_id": "acc_acme_001", "name": "Acme Corp" },
        { "account_id": "acc_pinnacle", "name": "Pinnacle Media" }
      ]
    }
  }]
}
```

## Design notes

### sync\_accounts and seller record systems

When an agent declares `(brand: {domain: "acme-corp.com"}, operator: "pinnacle-media.com")`, the seller looks up or creates records in its own system — CRM, OMS, ad server, or billing platform.

`sync_accounts` is the buyer-side interface to the seller's record system. The seller may:

* Map the natural key to an existing account and return `status: "active"`
* Create a new record and return it immediately (`status: "active"`)
* Create a placeholder pending human review (`status: "pending_approval"`)
* Decline the request entirely (`status: "rejected"`)

`list_accounts` returns all records the seller has mapped for this agent — including pending and rejected entries. The agent uses `list_accounts` to see the full state of its portfolio with this seller, not just active accounts.

### Accounts and insertion orders

An account represents a standing relationship — who gets billed, what rates apply, what credit is available. It is not a campaign or an insertion order.

Insertion orders and campaign flights are modeled as media buys via `create_media_buy`. The account determines *billing terms*; the media buy determines *what runs and when*. A single account can have many media buys over its lifetime.

### Operator revocation and caching

If a brand removes an operator from `authorized_operators`, existing active accounts are not automatically deactivated. Revocation is eventual, not immediate — similar to how `ads.txt` changes propagate on the supply side.

Sellers SHOULD respect standard HTTP caching headers on `brand.json` and re-validate periodically. A reasonable cache TTL is 24 hours.

### Brand identity for SMBs

Domain-based identity via `/.well-known/brand.json` works for organizations of any size — it's a static JSON file that can be hosted on any web server.

For organizations that cannot host files on their domain, the `authoritative_location` field in `brand.json` allows the house domain to redirect to a hosted location:

```json theme={null}
{
  "house": {
    "domain": "local-bakery.com"
  },
  "authoritative_location": "https://registry.agenticadvertising.org/brands/local-bakery.com"
}
```
