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

> Map incoming buyers to ad-server advertisers for ESA-backed sources

Buyer routing decides which ad-server advertiser a buyer's spend books against when your storefront draws from an embedded sales agent (ESA). Every incoming buyer resolves to exactly one advertiser: a per-buyer **mapping** if one matches, otherwise the storefront's **default advertiser** catch-all.

* **Default advertiser** — the catch-all every unmatched buyer routes to. Set it once with `PUT /esa/{esaId}/default-advertiser`, whichever ad server backs the source. Until it is set, this source contributes a blocker to the **Advertiser for live buys** readiness check. Google Ad Manager also reports a `Default GAM advertiser` setup task.
* **Per-buyer mappings** — override the default for a specific buyer, keyed on `operatorDomain` (optionally narrowed by `brandHouse`, `brandId`, or `principalId`). A matching mapping wins over the default.
* **Recent buyers** — the buyers the ESA has actually seen, with whether each resolved through the default or a specific mapping, so you can spot buyers that need their own advertiser.

## Finding an advertiser id

The provider-neutral endpoint returns bounded advertiser pages for supported ad
servers. Google Ad Manager also keeps its dedicated filtered search endpoint:

| Ad server         | Endpoint                                                                                  | How it reads                                |
| ----------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------- |
| Google Ad Manager | `GET /esa/{esaId}/advertisers`; use `GET /esa/{esaId}/gam/advertisers` for name filtering | Bounded pages from the synced cache         |
| FreeWheel         | `GET /esa/{esaId}/advertisers`                                                            | Bounded authoritative sync and cached pages |
| AdsWizz           | `GET /esa/{esaId}/advertisers`                                                            | Provider-neutral roster pages               |
| SpringServe       | —                                                                                         | No advertiser entity exists                 |

Pass `limit` (up to 500) and `cursor` to page through the provider-neutral
endpoint. Follow `nextCursor` until it is `null`. `authoritative: true` means the
source completed its bounded read; `truncated: true` or a non-empty `errors` list
means the response must not be used to infer that an omitted advertiser was
removed.

<Note>
  Setting the **default advertiser** works on Google Ad Manager, FreeWheel, and
  AdsWizz sources. **Per-buyer mappings** are still Google Ad Manager only — on
  FreeWheel and AdsWizz, every buyer routes to the default advertiser.

  SpringServe does not support a tenant default through this buyer-routing
  surface: it has no advertiser in its model at all, so there is nothing to route
  to.
</Note>

## Setting it without the API

You do not have to call the API to set a default advertiser. Open the **ad
server source** page in your storefront, and the source's "Set default
advertiser" action lists the advertisers on your ad server and writes the one
you pick. This is the same read and write documented below, so it works for
Google Ad Manager, FreeWheel, and AdsWizz alike.

Two differences show up in the picker, and they follow your ad server, not
Apostra:

* **Search.** Google Ad Manager serves a searchable advertiser cache, so typing
  narrows the list at the source. Other ad servers return a bounded roster page,
  which the picker filters in place.
* **Creating an advertiser.** Only Google Ad Manager lets Apostra create one
  for you, so the "create a new advertiser" option appears there. Elsewhere,
  create the advertiser in your ad server first, then pick it.

An inventory sync can succeed even when the ad-server credential cannot see any
advertisers: inventory and companies are separate permissions. If the
advertiser list reports zero records, confirm that Apostra service
account has advertiser read access. Then retry. Do not interpret a healthy
inventory count as proof that advertiser access is configured.

For a managed GAM connection, use the dedicated **Apostra - Default**
advertiser as the fallback. You do not need a GAM advertiser per end advertiser
unless you want a buyer-specific routing override. Safe no-spend tests use a
separate **Apostra - Sandbox** advertiser; Apostra never falls back to
the production default advertiser for a sandbox test.

## Why readiness blocks without one

A live buy has to book against an advertiser, so `GET /readiness` reports an
**Advertiser for live buys** check and it blocks going live. Without a resolved
advertiser every buy outside the sandbox fails terminally, so a storefront that
reported itself ready would be telling you something untrue.

The check reads the advertiser from your ad server, not from a copy held by
Apostra, so mapping one clears the check on your next readiness read with
nothing else to do.

Three things follow from how routing actually works:

* **Sandbox tests still run.** A no-spend test routes to the **Apostra -
  Sandbox** advertiser and never touches this chain, so the sandbox test is
  admitted even while the check is open. This is also why a passing sandbox test
  is not evidence that live buys will work — the two use different advertisers.
* **Several ad servers means the storefront stays live.** If you sell through
  more than one ad server, the check blocks only when *none* of them can route a
  live buy. When one is missing an advertiser and the others can still transact,
  readiness names that ad server as a warning and your storefront keeps selling
  the inventory that works.
* **Ad servers with no advertiser are exempt.** SpringServe has no advertiser in
  its model, so the check never applies to it — it would be a requirement you
  could never satisfy. Google Ad Manager, FreeWheel, and AdsWizz all have a
  default advertiser, and the check links each of them to the picker on the
  ad-server source page. If your ad server has a default advertiser but no
  picker, the check asks you to contact us instead of pointing at a control that
  is not on the page.

All examples use the storefront base URL:

```
https://api.apostra.com/api/v2/storefront
```

Authenticate every request with `Authorization: Bearer $SCOPE3_API_KEY`. The `{esaId}` path parameter is the embedded sales-agent connection id.

## Task reference

<CardGroup cols={2}>
  <Card title="List adapter advertisers" href="/v2/storefront/buyer-routing/tasks/list-adapter-advertisers" icon="list">
    `GET /esa/{esaId}/advertisers` — bounded provider-neutral advertiser pages
  </Card>

  <Card title="List GAM advertisers" href="/v2/storefront/buyer-routing/tasks/list-gam-advertisers" icon="list">
    `GET /esa/{esaId}/gam/advertisers` — cached GAM advertiser records
  </Card>

  <Card title="Ensure GAM advertiser" href="/v2/storefront/buyer-routing/tasks/ensure-gam-advertiser" icon="plus">
    `POST /esa/{esaId}/gam/advertisers/ensure` — create or find by name
  </Card>

  <Card title="Set default advertiser" href="/v2/storefront/buyer-routing/tasks/set-default-advertiser" icon="star">
    `PUT /esa/{esaId}/default-advertiser` — the catch-all advertiser
  </Card>

  <Card title="List buyer mappings" href="/v2/storefront/buyer-routing/tasks/list-buyer-mappings" icon="table-list">
    `GET /esa/{esaId}/buyer-advertiser-mappings` — per-buyer overrides
  </Card>

  <Card title="Create buyer mapping" href="/v2/storefront/buyer-routing/tasks/create-buyer-mapping" icon="link">
    `POST /esa/{esaId}/buyer-advertiser-mappings` — route one buyer
  </Card>

  <Card title="Update buyer mapping" href="/v2/storefront/buyer-routing/tasks/update-buyer-mapping" icon="pen">
    `PATCH /esa/{esaId}/buyer-advertiser-mappings/{mappingId}` — edit a mapping
  </Card>

  <Card title="Delete buyer mapping" href="/v2/storefront/buyer-routing/tasks/delete-buyer-mapping" icon="trash">
    `DELETE /esa/{esaId}/buyer-advertiser-mappings/{mappingId}` — remove a
    mapping
  </Card>

  <Card title="List recent buyers" href="/v2/storefront/buyer-routing/tasks/list-recent-buyers" icon="clock-rotate-left">
    `GET /esa/{esaId}/recent-buyers` — buyers seen and how they resolved
  </Card>
</CardGroup>
