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

# Connect your sales agent

> How Apostra uses AdCP to integrate your sales agent as a storefront inventory source — the seller (supply) side.

This page is for a **seller bringing their own AdCP sales agent into Apostra as supply** — how Apostra uses
the [Ad Context Protocol (AdCP)](https://docs.adcontextprotocol.org) to connect *your* agent as a storefront
inventory source.

<Info>
  **This is the storefront (sell-side) view.** If you instead want to connect Claude, ChatGPT, or another assistant
  as a *client* of Apostra API, see [Built for agents](/v2/setup/built-for-agents). For how Apostra
  itself consumes AdCP as a buyer (Discover Products, campaigns), see
  [How Apostra uses AdCP (buy side)](/v2/concepts/adcp-on-the-buy-side).
</Info>

<Note>
  An Apostra-hosted Seller with a verified publication CNAME is called by
  buyers at `https://<seller-cname>/adcp/mcp`; the shared-host fallback is
  `https://api.apostra.com/seller/{platformId}/mcp`. The retired
  `/storefront/{platformId}/mcp` route returns 404. This does not change the URL
  for an external `AGENT` source: publish and connect that agent's own endpoint.
</Note>

## Ways inventory comes in

A storefront draws supply from one or more sources:

* **`AGENT`** — an external AdCP-compatible sales agent Apostra connects to. *This is the "bring your own
  agent" path and the focus of this page.*
* **`MANAGED_SALES_AGENT`** — an operator-owned ad server with Apostra-managed sales-agent plumbing.
* **`LINKED_STOREFRONT`** — wholesale inventory from the pool of listed, transacting storefronts.
* **`MODULAR_SOURCE`** — composed from private modules (avails, booking, trafficking, reporting).

See [Choosing a source](/v2/storefront/inventory-sources/choosing-a-source) for the full comparison.

## What you bring (external `AGENT`)

There are two parts: the **technical setup** for your agent, and **bringing the inventory** it sells.

### 1. Technical setup

1. **A conformant AdCP agent endpoint** that advertises its `supported_protocols` and versions via
   [`get_adcp_capabilities`](https://docs.adcontextprotocol.org/docs/protocol/get_adcp_capabilities). Apostra
   supports AdCP `3.0` and `3.1` — see [AdCP versioning & negotiation](/v2/concepts/adcp-versioning) for how the
   version your agent serves is negotiated. If you discovered the agent from a
   publisher, use the executable URL in AAO's selected
   `authorized_agents[].url` entry. The publisher's `adagents.json`, AAO
   `hosting.resolved_url`, and an `authoritative_location` are identity-document
   locations, not agent endpoints.
2. **Signing keys (JWKS)** — set up your request/webhook signing keys so Apostra can verify your agent's
   RFC 9421-signed calls and you can verify ours. This is a required step, not an afterthought, if you sign with
   RFC 9421 — for webhook verification specifically, Apostra discovers your JWKS through
   `brand.json → agents[].jwks_uri` (see item 5 below), not a standalone `jwks.json` URL. See
   [Authentication](/v2/authentication).
3. **Credentials** for authenticating to your agent endpoint.
4. **Real-time targeting (TMP)**, if you serve through it — connect the TMP Router so serve-time targeting and
   macros resolve. See [Real-time targeting](/v2/storefront/tmp/overview).
5. A **`brand.json`** at `/.well-known/brand.json` on your agent's origin. Optional if you never sign or verify
   over RFC 9421 — but **required** the moment you do: it's how Apostra resolves the JWKS for verifying your
   RFC 9421-signed webhook deliveries (e.g. the storefront-catalog invalidation webhook). Also brands the agent as
   operator-owned ("I own this agent") for identity purposes.

For OAuth sources, the standards path is MCP OAuth protected-resource discovery
at the endpoint's well-known URL. That document advertises at least one
`authorization_servers` issuer, and the issuer publishes RFC 8414
authorization-server metadata (or OpenID configuration) containing its
authorization and token endpoints. The authorization server may use a different
origin from the agent.

If an older gateway validates a resource-specific token audience but does not
publish protected-resource metadata, set `oauthAudience` while registering a
new OAuth identity or updating an existing source. Apostra sends that same
public URI as both the Auth0 `audience` and RFC 8707 `resource` and stores it
with the OAuth configuration. Update returns a fresh authorization URL for
consent when discovery and flow storage succeed; a successful response without
`oauth` means the audience was stored and the same update should be retried to
start consent. Create returns a URL only for a newly registered identity when
discovery and flow storage succeed. If that block is absent, use [Start agent
OAuth](/v2/storefront/agents/tasks/start-agent-oauth) after creation; retrying
create reuses the identity and does not initialize consent. If the endpoint
reuses an existing identity, create reuses that identity's OAuth configuration
instead. Omit the override when protected-resource discovery supplies the
resource. The override does not replace
authorization-server metadata: an older agent must still publish that metadata
directly on its own origin.

Every discovered network destination must resolve to a public endpoint;
private, loopback, link-local, or unresolvable destinations are rejected. An
explicit audience is a resource identifier rather than a URL Apostra
fetches, but it must still be a public HTTPS URI and cannot name a private or
local address.
Apostra delegates discovery, dynamic client registration, PKCE/state, and
authorization-code exchange to the AdCP client SDK.

### Connect it in Apostra

In any MCP Apps host, call `prepare_external_sales_agent_connection` to open
the focused **Connect sales agent** Task. Enter the endpoint, protocol, and
credentials inside that secure surface; credentials are never passed through
the model. The first version offers no authentication, bearer token, and basic
authentication—the methods the existing sales-agent runtime executes without a
provider-specific adapter. The shared connection-definition model also supports
typed API-key, OAuth 2.0, JWT, and platform-service-account methods for
integrations that declare and implement them; it never accepts custom executable
header templates. After connection, use Source diagnostics for compliance,
discovery, and health checks.

The Task pins the version of the connection definition used for setup. Existing
API clients that do not send a connection definition continue through the legacy
request shape while integrations migrate. In both paths, credentials belong to
your storefront account: Apostra stores the secret in its credential store,
keeps only a client-scoped reference in connection metadata, and returns only
whether credentials are configured. Secret values and secret references are
never returned to the Task or model.

### 2. Bringing inventory — onboard your publishers

You don't hand Apostra a separate list of formats and inventory — that comes from **onboarding the publishers
your agent sells for**. For **each** publisher (that's *you* if you're a publisher; *each partner* if you're a
sales house or network), that publisher's properties must authorize your agent:

* An [`adagents.json`](/v2/storefront/tasks/discover-agents) lives on the **publisher's domain** (not necessarily
  yours) and authorizes your agent for that publisher's **properties**. Properties can be non-web (CTV, audio,
  app, DOOH), so this is about properties, not just websites.
* Authorization is tied to the publisher domain — an agent is authorized only for properties a publisher has
  granted it (presence in `authorized_agents[]` alone isn't sufficient).
* A publisher's `adagents.json` is also where their placements, formats, and other property details are declared.

So a sales house representing 50 publishers needs each of those 50 publishers' domains to authorize the agent —
the authorization is per-publisher, across all your partners.

## Conformance: understand the AAO signal

The **AAO registry** is the source of truth for agent registration and compliance
verdicts. Apostra reads those registry results; it does not define AAO
storyboards itself.

What "compliance" means operationally: your agent should pass the AAO storyboards
for the kind of agent you are. A sales agent passes the base sales-agent
storyboard plus the ones for what you sell — guaranteed, non-guaranteed, retail,
and so on.

Apostra uses AAO signals in three different ways:

* **Registration** is a connect-time gate. An external `AGENT` source must be
  registered with AAO before it can be connected.
* **Compliance** is advisory for source connection and storefront activation. A
  non-passing verdict is surfaced as a warning, but it does not block going live.
* **Marketplace listing** is a separate Apostra review step after activation.
  AAO compliance is an important signal in that review, but it is not the same
  thing as the activation gate.

See [Storefront onboarding](/v2/setup/storefront-onboarding#connect-inventory-sources)
for the connect-time table and [Storefront overview](/v2/storefront/overview) for
marketplace review.

### Product format compliance

Product format compliance is separate from the AAO storyboard verdict. A
product may publish URL-free canonical `format_options[]` or an exact legacy
`{agent_url, id}` reference that Apostra's compatibility mapping can
resolve. Exact legacy references remain supported without a sunset;
Apostra never guesses from the ID text.

When canonical-format compliance is enabled for your storefront, \*\*Seller Setup

> Inventory sources\*\* flags unresolved catalog products from active external
> sales-agent sources and names the affected source and count. A product from an
> existing or newly connected source passes when it publishes at least one usable
> canonical option. For a legacy product with multiple references, Apostra
> keeps every successfully projected option and reports an unsupported remainder
> as an advisory; one unsupported reference does not suppress the product. A
> product with no usable canonical option is withheld on its own until corrected.
> Neither case implicitly changes Source request eligibility or storefront
> transaction eligibility.

Catalog age is handled by the separate refresh policy: an interpretable
declaration does not become noncompliant when its cache entry ages. Because
pass-through `get_products` responses are brief-specific, Seller Setup uses a
source's public catalog evidence when it is available and otherwise falls back
to its account-conditioned evidence. The newest declaration for a product
replaces older observations across the wholesale and pass-through paths. Buyer
discovery and purchase still recheck the relevant account context and selected
product before serving. Replace an unsupported seller-specific reference with
an exact shared-catalog reference or publish an interpretable custom canonical
declaration. Managed and modular sources continue to use their own readiness
contracts.

When a source has no persisted product declarations, a buyer brief can still
perform a non-serving source revalidation: Apostra returns no products from
that source on the call but records the relevant public or account-conditioned
catalog evidence. A corrected product with the same ID clears the diagnostic on
the next readiness evaluation. A later response containing only interpretable
products also replaces an older pass-through observation whose products are no
longer returned for that brief. Cache age never turns a valid declaration into
a failure.

<Note>
  The depth of `adagents.json` / domain-validation handling is actively expanding through our AAO-integration work;
  treat this as current behavior, not the final shape.
</Note>

## How your agent participates (the AdCP surfaces we use)

Which surfaces light up depends on the storyboards your agent passes (above). Once connected, Apostra uses
these AdCP surfaces **against your agent**:

| AdCP surface                                                                                                                                                                                                      | What Apostra does with your agent                                                                                                                      |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`get_adcp_capabilities`](https://docs.adcontextprotocol.org/docs/protocol/get_adcp_capabilities)                                                                                                                 | Reads your declared protocols, versions, and capabilities at connect time.                                                                             |
| [`get_products`](https://docs.adcontextprotocol.org/docs/media-buy/task-reference/get_products)                                                                                                                   | Calls your agent as one seller in a buyer's discovery query; your products are stamped with your storefront identity.                                  |
| [`create_media_buy`](https://docs.adcontextprotocol.org/docs/media-buy/task-reference/create_media_buy) / [`update_media_buy`](https://docs.adcontextprotocol.org/docs/media-buy/task-reference/update_media_buy) | Routes a buyer's media buy to your agent; updates are guarded against capabilities your agent doesn't declare.                                         |
| [`get_media_buy_delivery`](https://docs.adcontextprotocol.org/docs/media-buy/task-reference/get_media_buy_delivery)                                                                                               | Pulls delivery from your agent and rolls it up.                                                                                                        |
| [`sync_creatives`](https://docs.adcontextprotocol.org/docs/creative/task-reference/sync_creatives)                                                                                                                | Syncs creatives to your agent, optionally through an operator creative-review queue. See [Creative reviews](/v2/storefront/creative-reviews/overview). |
| [`sync_accounts`](https://docs.adcontextprotocol.org/docs/accounts/tasks/sync_accounts)                                                                                                                           | Syncs buyer accounts to your agent.                                                                                                                    |
| [`check_governance`](https://docs.adcontextprotocol.org/docs/governance/campaign/tasks/check_governance)                                                                                                          | When a buyer brings a governance agent, your agent validates the action against it before fulfilling (see Governance below).                           |
| Webhook / request signing (RFC 9421)                                                                                                                                                                              | Verifies signed webhooks from your agent; our outbound calls are signed. See [Authentication](/v2/authentication).                                     |

### What your `sync_creatives` acknowledgement tells the buyer

Apostra reports a creative as live to the buyer only from what your agent
says about it. Per creative, the acknowledgement carries:

| Field         | How it is read                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`      | What you did with the creative: `created`, `updated`, or `unchanged` mean you accepted it; `failed` means you did not; `deleted` means you removed it. These are the only values AdCP defines — a review verdict belongs in `status`, not here.                                                                                                                                                                                                                                                                                                                                                                        |
| `status`      | Your review state — `approved` is the only live one. `pending_review`, `processing`, `suspended`, and `archived` all tell the buyer the creative will not serve yet, and the buyer sees that reason verbatim.                                                                                                                                                                                                                                                                                                                                                                                                          |
| `assigned_to` | The packages you bound the creative to. This must match the assignments the buyer asked for, or the sync is reported as unconfirmed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `platform_id` | Your creative's ID on the delivery platform — the ad server's ID, not the buyer's. Optional in AdCP, and Apostra records it as the evidence the buyer uses to reconcile the creative on your side. Send it as soon as you have one, on the acknowledgement or on a later creative webhook; you do not owe one for a creative you have accepted into your library but not yet trafficked, and its absence does not fail the sync. Never echo the buyer's `creative_id` back as your `platform_id` — that claims a platform record without proving one exists, and the creative is reported to the buyer as unconfirmed. |

`status` is optional in AdCP, and is read as advisory: if you run no review
lifecycle, omit it and an accepted `action` stands on its own. **If you do hold
creatives for review, you must send `status`** — an omitted status cannot mean
both "no review gate here" and "still waiting on mine", and Apostra reads the
first. Sending it is the difference between the buyer knowing a creative is
waiting on you and the buyer assuming it is ready to serve. If a creative is
suspended or archived on your side, say so — that is what stops a buyer from
counting it as delivering inventory.

Wholesale product and signal catalog requests are used only for a Source that
supports the Storefront-built path and whose Agent reports AdCP 3.1+ support.
An Agent-supplied Source instead receives buyer discovery and media-buy calls
through the normal surfaces above. An Agent may support both product paths, in
which case each Source selects one or both. These paths are not
separately monetized and are not inferred from endpoint behavior or catalog
contents.

The provider declaration and any both-path selection are currently reconciled by
Apostra support; the Source page displays them read-only. If diagnostics report a
missing declaration or incomplete wholesale contract, correct the Agent's
product, property, format, pricing, and execution data, then ask Apostra support
to refresh or reconcile the capability.

You can monitor your source's live behavior — per-call outcomes, errors, and latency — in
[Inventory-source diagnostics](/v2/storefront/inventory-sources/diagnostics).

## Governance agents

A buyer can bring their own **governance agent** — an external service that validates campaign actions (budget,
brand safety, regulatory compliance) before they execute — and **Apostra supports this**. We will support
third-party governance agents; a buyer doesn't depend on us to provide one.

What that means for you as a seller: **support the AdCP governance protocol** so you can transact with
governance-enabled buyers. When a buyer's governance agent is in play, your agent calls
[`check_governance`](https://docs.adcontextprotocol.org/docs/governance/campaign/tasks/check_governance) to
validate each action and fulfills as approved. The governance agent — not you — holds the consolidated audit
trail. (Campaign governance is an evolving AdCP surface; see the FAQ for credentials and audit.)

## FAQ

Questions sellers ask when integrating. Each answer is **what AdCP defines** (the protocol's source of truth) plus
**what Apostra does today** (the delta).

<AccordionGroup>
  <Accordion title="Do we have to comply with domain-validation requirements as a seller?">
    **AdCP:** publishers declare which sales agents may sell their inventory in a `/.well-known/adagents.json` file
    on their own domain (with `ads.txt` `managerdomain` delegation). Authorization is tied to the publisher domain
    — you publish an accurate declaration; you aren't required to run a validation algorithm yourself.

    **Apostra:** every publisher your agent works with must authorize the agent URL implied by the source model.
    We inspect the publisher's resolved `adagents.json` document using the fallback-aware resolution described in
    [Discover agents](/v2/storefront/tasks/discover-agents). If that resolved publisher file does not grant the
    agent, Apostra surfaces an advisory warning today and keeps setup/product authoring moving. Treat it as a
    publisher-owned authorization problem to fix before depending on that inventory. This is separate from AAO
    compliance: compliance is the registry's storyboard verdict; authorization is the publisher's `adagents.json`
    grant.
  </Accordion>

  <Accordion title="If we store bearer tokens for the governance agent, how are they rotated or replaced if compromised?">
    **AdCP:** a governance agent is an *external* service the buyer configures and registers via
    [`sync_governance`](https://docs.adcontextprotocol.org/docs/accounts/tasks/sync_governance), which hands the
    seller the agent's URL plus the credential to call
    [`check_governance`](https://docs.adcontextprotocol.org/docs/governance/campaign/tasks/check_governance). Per
    the shipped spec that credential **is** a Bearer token (`"schemes": ["Bearer"]`, at least 32 characters) — so
    bearer is the defined mechanism for this leg, not a discouraged one. **Rotation is replace-semantics:** re-run
    `sync_governance` with new credentials and they overwrite the old. AdCP does, however, treat a static,
    long-lived shared bearer as an *interim floor* for calls that mutate state or commit spend, and is standardizing
    **RFC 9421 request signing** (keys published via the agent's JWKS, discoverable through `brand.json → agents[]`)
    — recommended in 3.0 and slated to become required for mutating calls in a later release. (The governance
    *decision* is separately returned as a signed `governance_context` JWS you verify against the agent's published
    keys — that signing is on the response, not on your stored call credential.)

    **Apostra:** treat the stored bearer as **short-lived and rotatable**, scope it tightly, and
    revoke-and-reissue on any suspected leak — don't rely on a single static shared secret, and move toward
    keypair-backed request signing as AdCP standardizes it. For the credentials you hold to call Apostra itself
    (signing keys, service tokens), rotation follows create-new → deploy → revoke-old. See
    [Authentication](/v2/authentication).
  </Accordion>

  <Accordion title="What audit logs / audit-trail data are required from the seller side for the governance agent?">
    **AdCP:** the **governance agent holds the consolidated audit trail** — a first-class, structured,
    timestamped, attributable record served via
    [`get_plan_audit_logs`](https://docs.adcontextprotocol.org/docs/governance/campaign/tasks/get_plan_audit_logs).
    The seller's role is to **validate** each action via `check_governance` and **fulfill** as approved; outcome and
    delivery reporting flow through the orchestrator. The seller is **not** required to maintain or hand over an
    audit-log store for the governance agent — keeping your own operational logs is part of running your business.
    (This is an AdCP 3.0 experimental surface and may change.)

    **Apostra:** when a buyer brings a governance agent, that audit trail lives with the governance agent, not
    with us. Our first-party [activity log](/v2/storefront/activity/overview) records actions taken in Apostra
    for platform accountability — it is separate from, and not a substitute for, the AdCP governance audit trail.
  </Accordion>
</AccordionGroup>

## Where the truth lives

<CardGroup cols={2}>
  <Card title="AdCP specification" href="https://docs.adcontextprotocol.org" icon="book">
    The protocol's source of truth — tasks, authorization, and governance.
  </Card>

  <Card title="Choosing a source" href="/v2/storefront/inventory-sources/choosing-a-source" icon="server">
    Compare AGENT, managed, linked, and modular sources.
  </Card>

  <Card title="Discover agents" href="/v2/storefront/tasks/discover-agents" icon="magnifying-glass">
    How `adagents.json` resolution and authorization work.
  </Card>

  <Card title="Storefront overview" href="/v2/storefront/overview" icon="store">
    AAO compliance and marketplace listing for sellers.
  </Card>
</CardGroup>
