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

# v3 Preview Limitations

> Compatibility, lifecycle, and operational limits of the v3 preview.

Commercial identity setup has a [text-only workflow](https://docs.apostra.com/v2/setup/v3/identity-setup.md).
Public brand lookup and advertiser linking cannot create, edit or publish
`brand.json`, or refresh a saved snapshot in place. Buyer AAO OAuth proof has no
portable v3 initiation or callback flow; v3 can inspect its evidence or file a
support ask. Seller domain review progress is available through
`get({ kind: "seller", include: ["identity"] })`. Organisation names, login
domains, members and roles remain outside the commercial identity tools.
Identity confirmation is opt-in for operator saves and corrections to an
existing advertiser's brand through `identityContract: "confirmed-v1"`.
Earlier payloads retain their existing behaviour; this
release does not require those clients to adopt the new confirmation exchange.

## Availability and compatibility

* v3 is available to every authenticated Buyer and Seller Account.
* The v2 buyer API is closed to new API clients and switches off on 1 December
  2026, except the conversion endpoint
  `POST /api/v2/buyer/advertisers/{advertiserId}/log-event`, which stays open.
  See [Move a v2 buyer REST integration to V3](https://docs.apostra.com/v3/migrate-from-v2-rest.md). The
  v2 admin API remains stable. In production, the v2 storefront (seller) API
  refuses external callers with `GONE` and a pointer to v3.
* v3 is served over MCP and over the [v3 HTTP API](https://docs.apostra.com/v3/http-api.md). The HTTP API
  exposes the public v3 operation catalogue at
  `POST /api/v3/tools/<operation>`; app-only helpers that in-chat Pages use are
  not part of it. It is not a replacement for the whole v2 REST surface: admin
  operations outside the catalogue stay on the stable v2 admin REST API.
  Sellers use v3 only.
  `/api/v3/documents` is limited to authenticated exact reads and downloads of
  approved public immutable agreement revisions. Discovery, comparison, private
  documents, and governing-agreement selection are not yet REST resources.
* The unversioned buyer MCP alias resolves to the v2 buyer MCP endpoint, which
  closes to external callers on 1 December 2026 with the v2 buyer API. The
  unversioned seller MCP alias redirects to the v2 storefront endpoint, which
  refuses external callers in production; sellers connect to `/mcp/v3`.
* Organisation accounts currently provide navigation and shared tools, not an
  organisation-specific noun catalog.
* The account kinds you can reach determine which buyer or seller catalog
  appears.

`get_status` remains available in an unclassified account so a session can
orient and find the Buyer or Seller Account to name. No domain catalog is
implied by a successful connection to an unclassified account.

## Buyer limitations

The Buyer surface supports advertiser and campaign authoring, creative
management, proposal requests, media-buy staging, and explicit campaign launch.
The following gaps remain:

| Capability | Current behavior |
| - | - |
| Creative generation | v3 can save and attach a finished creative, including audio, but it does not generate or revise the content. Generate externally and hand off the approved asset. |
| End-to-end workflow orchestration | v3 exposes the typed buying tools; the integrating application or its external agent owns durable workflow state, retries, and human checkpoints. There is no hosted end-to-end orchestrator in the preview. |
| Buyer-agent orchestration | External buyer-agent identity, credentials, exact advertiser access, and machine-notification administration are available through the buyer console and stable v2 API. A public v3 `buyer_agent` noun and hosted runtime are not in the current v3 catalog; treat them as unavailable until advertised by `tools/list`. |
| Campaign cancellation | `desiredPhase: "canceled"` is irreversible, requires the current `expectedRevision`, and cancels the campaign plus every live media buy. A guaranteed committed buy goes to operator approval and keeps delivering until approved. Seller confirmation is asynchronous: requested outcomes are `canceled`, `cancel_pending`, or `cancel_failed`; a buy already terminal retains its observed phase. The parent remains `ending` until every child is terminal. To stop one buy, use `save_media_buy` with `isCanceled: true`, or pause it with `isPaused: true`. Retry pending or failed buys with the latest revision; archive remains a separate visibility operation. |
| Campaign restore | `isArchived: false` restores an archived campaign in its preserved phase. Archiving is a visibility-only operation and does not retire its media buys. |
| Campaign autonomy | Persisted per campaign. |
| Clear campaign brief or flight | `null` is currently a no-op, not a clear operation |
| Proposal evaluation policy | Instructions and policy fields are recorded but not applied to ranking |
| Media-buy creation flight | `save_media_buy` accepts `flight` when staging from products or accepting a proposal. A specific `startAt` must be a future UTC-day datetime; use `"asap"` to start immediately. |
| Media-buy top-level budget | `budget` is accepted when staging from products, accepting a one-allocation proposal, or updating a draft when the resulting buy has one product. Direct multi-product creation and updates use `products[].budget` per product; multi-allocation proposals retain their allocation. |
| Proposal settlement and routing | One `save_media_buy` proposal acceptance creates one media buy. All proposal allocations must resolve to one settlement currency and seller route; a proposal spanning currencies or seller routes is rejected before it is claimed or staged. Request separate proposals by currency or seller route. |
| Adding a product to a staged buy | Not supported by the update path; stage a new media buy (or archive the draft with `isArchived: true` and stage again). `save_media_buy` can stage a separate new buy for a new product or seller on an active campaign; it does not change an active buy. A product already owned by any non-terminal buy cannot be staged again; `save_media_buy` returns an `INVALID_STATE` refusal naming that buy so you can select another product or cancel it first. Retrying the same create request with the same `idempotencyKey` returns that original result with `replayed: true`; use a new key only after changing the request. |
| Same product staged twice on one buy | Each line item on a media buy read carries a `lineItemRef`; pass it as `products[].lineItemRef` to change or remove exactly that line item. Without it, an update to a repeated product is refused as ambiguous |
| Changing a line item's pricing option | Draft only. `products[].pricingOptionId` must be one of the product's published options; moving to a fixed-price option clears a stale bid unless `bidPrice` is sent in the same call |
| Meta Sales conversion tracking | Meta requires a Pixel/Dataset for Sales campaigns, and for some Traffic campaigns depending on optimization goal. When the buy's optimization goal names an event source mapped on the seller account, the mapped Pixel/Dataset is sent for you. Otherwise pass it as `products[].pixelId`: there is no auto-select, even when the connected ad account has exactly one authorized Pixel/Dataset. A missing or unauthorized ID fails with the candidate Pixel/Dataset IDs to choose from. |
| Meta Page selection | Pass `products[].pageId` when the connected ad account has more than one authorized Facebook Page; the server auto-selects when exactly one is authorized. |
| Meta Instagram Direct destinations | Pass `products[].instagramActorId` for Instagram Direct Conversations and Instagram-based Lead Generation when the account has more than one authorized Instagram account. The validation error does not enumerate candidates; read them from Meta Business Settings or a product's `executionResources` (`platform_identity`/`destination`). |
| Meta lead-to-message welcome flow | Pass `products[].welcomeMessageFlowId` for Messenger, Instagram Direct, and WhatsApp Lead Generation products. Required for these products; never auto-selected, since it binds the buy to a specific automated conversation. |
| Meta Instant Forms | Pass `products[].leadFormId` for Meta Instant Forms products. The form must belong to the Page selected by `pageId` (or the auto-selected Page). |
| TikTok App Promotion | Pass `products[].appId`, one of the advertiser app IDs authorized on the account. |
| Media-buy archive | `isArchived: true` archives a DRAFT, FAILED, CANCELED, or REJECTED buy. A dispatched buy cannot be archived; request cancellation with `save_media_buy({ mediaBuyId, isCanceled: true })`, then archive it once cancellation is terminal. A completed buy stays as the delivery record and cannot be archived or canceled |
| Media-buy restore | `isArchived: false` is not supported; an archived buy is retired for good |
| Buyer media-buy archive state | Reads expose the media buy's actual `isArchived` state; pass `filter.isArchived: true` to search archived media buys |
| Proposal evidence on media-buy reads | Preserve `proposalSource` from the acceptance response; later Buyer reads do not include it |
| Tracked campaign adoption | Use the existing v2 adopt or duplicate workflow |
| Tracker delivery and rendered preview | Advertiser and campaign tracking configuration, inheritance, and headless `test_creative_macros` reports are available; attaching effective trackers to outbound creatives and rendering the report inside creative review remain follow-up work |

Launching is supported, but only as a separate, two-call update to an existing
campaign: a preview with `desiredPhase: "active"` and no `confirmLaunch`
returns the campaign revision and what would launch; the confirm call sends
`confirmLaunch: true` with that `expectedRevision`. Both calls require their
own `idempotencyKey`. See
[Launch a campaign with explicit confirmation](https://docs.apostra.com/v3/tool-reference.md#launch-a-campaign-with-explicit-confirmation).

A failed launch may report a partial write because downstream execution state
was attempted. Re-read before retrying.

## Seller limitations

* Every Media Company account can
  use `save_advertiser`, `save_campaign`, `save_creative`,
  `save_creative_collection`, `request_proposals`, and `save_media_buy`
  directly from its Seller account. Sandbox Advertisers are available to every
  Media Company. Live Advertisers and campaigns come with Merchandising and are
  available only to organizations on a current Merchandising plan. Every
  operation is pinned server-side to that company's own Storefront. A
  missing, foreign, or wider Storefront, Proposal, qualified Product, or
  existing MediaBuy scope is rejected before dispatch.
* Integrated `search`/`get` can list and read authorized sandbox or live
  Advertisers, scoped Campaigns, Creative, Creative Collections, Proposals, and
  buyer-side MediaBuys.
  `get(kind: "seller", id, advertiserId, include: ["products"] )`
  opens the company's own wholesale catalog, so callers can pass qualified
  Products directly to `save_media_buy` without requesting Proposals. When a
  Product advertises `signal_targeting_options`, its eligible Signals can be
  selected through `products[].targetingOverlay`.
* Merchandising changes account access only. Live campaign launch still
  requires ordinary source currency compatibility, account mapping, publisher
  authorization, funding, standing, and any seller-side approval. Creative
  approval does not block launch: a destination that needs an approved creative
  waits to deliver. No sandbox or publish-validation bypass applies to live
  traffic.
* Seller `search(kind: "media_buy", filter: { campaignId })` or
  `filter: { advertiserId }` selects the integrated Buyer projection. Omitting
  both selects the Seller inventory/execution projection.
* Seller Accounts use the left navigation's three modes: **Storefront**,
  **Managed campaigns**, and **Settings**. Setup progress appears at the top of
  Storefront. Managed campaigns lists the
  account's sandbox Advertisers, plus live own-supply Advertisers once the
  account has live managed campaigns; selecting an Advertiser
  opens its Campaigns, Creatives, and Reporting work. **Add advertiser** in
  Managed campaigns or Campaigns opens the shared Advertiser Setup Task. It creates
  through `save_advertiser`, refreshes the roster, and can switch directly into
  the new Advertiser. Sandbox is the only choice unless the account has live
  managed campaigns (Merchandising). Campaign creation and delivery requests stay in
  Apostra so the same V3 own-supply guards apply.
  Buyers, under **Your storefront** in Storefront, lists external AdCP
  counterparties separately; selecting one shows
  media buys, synced creatives, and Delivery on your inventory for that
  relationship, plus its account admission case when setup needs attention.
  Managed campaigns uses the shared buyer advertiser picker and work navigation
  for the accounts the seller operates; protected System accounts are read-only.
  Agents are managed from the organization's Developer account, not from the
  seller navigation.
  Browse media partners, Connections, Buyer Setup, and unbound production Advertisers
  are not part of this preview.
* Shared Page hydration permits only three Seller-key Buyer REST reads: the
  Advertiser roster (sandbox by default; live only with Merchandising),
  Campaign listing for an explicitly bound
  Advertiser in either environment with wider-supply rows removed, and that
  Advertiser's promoted Creative list in read-only mode. Buyer REST detail,
  mutations, and reporting remain unavailable to Seller keys. The Advertiser
  Setup Task writes through the public V3 `save_advertiser` contract instead.
* Portable callers can use
  `get_delivery({ report: "campaign_delivery" })` with explicit metrics,
  dimensions, a date range of at most 90 inclusive days or
  `range: { lifetime: true }`, and optional advertiser, campaign, or media-buy
  filters. A `packageId` filter requires a bounded date range (not lifetime),
  because the reporting operation fetches all campaign data before filtering by
  package. Integrated Media Companies must name an own-supply advertiser,
  campaign, or media buy.
* Portable callers can use the additive
  `get_delivery({ report: "live_campaign_delivery" })` mode with one exact
  `campaignId` and a bounded date range or `range: { lifetime: true }`. It reads
  the connected provider and does not accept metrics, dimensions, other
  filters, or a cursor.
* Some credential, payout, approval, retry, and reassignment work intentionally
  remains in Pages rather than model-authored tools.
* `save_media_kit` remains for compatibility but is deprecated; new clients
  should author Listing identity through `save_seller`'s `listing`
  field. `get`/`save_media_kit`'s deprecated `kind`/field is now canonically
  spelled `listing`, with `media_kit`/`mediaKit` accepted as deprecated
  aliases for the same handler.
* Seller delivery is seller-reported. It is not Buyer measurement and does not
  establish billing eligibility by itself.

## Catalog and host differences

The runtime catalog may be narrower than the tables in these docs because of
account kind, permissions, feature rollout, and MCP App visibility. A principal
that can reach both Buyer and Seller Accounts instead receives their deduplicated
union at connection time, so hosts that cache `tools/list` retain both workflows
whichever account a call names. Tools remain authorized only for the account a
call names. Always use `tools/list` and `get_status`, and send `accountId` on
every call.

A stale tool call fails with typed wrong-account guidance that names the
reachable accounts that can run it, rather than crossing the account boundary.
`switch_account` is retired and still runs only from cached tool lists.

## Payload, connection, and timing limits

* Structured responses over 200 KB are truncated as a safety backstop.
* One MCP connection is held open for at most 30 minutes; reconnect with the
  existing session when the client uses sessionful MCP.
* A single tool call is also limited to 30 minutes.
* Deploys can close connections and eventually interrupt long in-flight calls.
* `request_proposals` durably schedules the full eligible cohort. Each
  background seller attempt has a 45-second bound; terminal result pages carry
  at most 50 seller outcomes and at most five bounded product projections.
  Product-heavy sellers continue on the returned cursor. Diagnostic pages
  carry at most 100 sanitized outcomes.
* A `productQueryId` returned by `request_proposals` or a `wholesale_product`
  search books into one campaign. Booking the same products into another
  campaign needs a new `request_proposals` round or search.
* A returned `productQueryId` stays stageable while the buyer deliberates. The
  discovery-analytics sweep marks a product query inactive after 60 minutes
  without activity (`DISCOVERY_SESSION_INACTIVITY_MS`, an infrastructure
  setting), but `save_media_buy` reopens such a query on first use, so a
  long deliberation does not lose the offer. A query that was already
  executed or replaced is refused with `PRODUCT_QUERY_EXPIRED`; call
  `request_proposals` or search again. A quoted proposal expires at the seller's own
  `validUntil` or after 90 days, whichever comes first; `PROPOSAL_EXPIRED`
  names which window lapsed.
* Seller delivery ranges are inclusive and limited to 90 days.

Long-running work should use an asynchronous workflow where one is available
instead of holding a single MCP call open.

## Direct-client model usage

Apostra can observe API calls, server-side model calls, and Apostra-hosted
turns. It cannot observe the input/output token usage or model cost incurred by
an external MCP client's own model. Integrators remain responsible for that
client-side budget and telemetry.

## Choosing v2 or v3

Buyer integrations move to v3. The v2 buyer API is closed to new API clients
and switches off on 1 December 2026; see
[Move a v2 buyer REST integration to V3](https://docs.apostra.com/v3/migrate-from-v2-rest.md). The
conversion endpoint `POST /api/v2/buyer/advertisers/{advertiserId}/log-event`
stays open. If your integration depends on a workflow listed as incomplete
above, contact Apostra support before the switch-off.

Sellers use v3 only. Admin operations outside the v3 catalogue stay on the v2
admin REST API.


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