Skip to main content
This page explains what Apostra requires from a Sales Agent before we send it buyer work, and the practices that make that work dependable. It is for the developer of the Agent, not for a sales or onboarding questionnaire.

What is enforced today

Routing buys by declared features is being rolled out. Today, when a buy has a property list, we send the list only to Agents that declare property-list support. We may still return Products from an Agent that does not declare support, and may send that Agent a buy without the property list. Declare every feature your Agent honours so the routing can apply it correctly. The seven-day behaviour baseline below is our published requirement, but we do not yet calculate or enforce it automatically. We are rolling out automated checks for it; today, our team reviews the calls we make to your Agent with you. Do not treat a missing automated check as permission to skip a requirement.

How we assess an Agent

We use evidence from our own calls to your endpoint. That includes the get_adcp_capabilities, sync_accounts, and get_products calls we make, as well as requests made while discovering inventory and handling buys. We measure the response your Agent sends, its timing, task progress, and whether returned products honour the request. We do not accept a self-reported claim as proof that an Agent behaves this way.

Required declarations

AdCP 3

What it is. Your get_adcp_capabilities response must include major version 3 in adcp.major_versions. Responses must validate against the schema for the version we negotiate. Why buyers care. A buyer needs the same contract that your Agent says it supports, so a discovery result or buy does not fail when it reaches your system. How we measure it. We call your capabilities endpoint and validate the responses we receive at the negotiated version.

A supported billing model

What it is. Declare agent, operator, or both in supported_billing. This is a seller-wide declaration, selected for each account in sync_accounts. We review advertiser billing case by case. Why buyers care. The billing model determines who can operate the buy and settle it without a manual intervention after the buyer is ready to transact. How we measure it. We read the billing declaration from the account and capability responses we call, rather than relying on a separate statement from your team.

A creative kind we supply

What it is. At least one Product must accept one of the creative kinds we supply in format_options: display_tag, video_vast, or audio_daast. Why buyers care. A buyer can only place a buy if Apostra can deliver a creative that the Product accepts and can measure. How we measure it. We inspect the Products returned by our own get_products calls.

Per-buy features

Property-list targeting

What it is. Property lists are a per-buy feature. In AdCP 3.1, declare media_buy.features.property_list_filtering and, for each applicable Product, property_targeting_allowed. If your Agent negotiates AdCP 3.2, also declare media_buy.execution.targeting.property_list and property_list_exclude, plus overlay_support.property_list on each applicable Product. Why buyers care. A property list lets a buyer direct a buy to the intended publishers, stations, or networks. It applies to every channel, including linear TV and radio. How we measure it. We read these declarations from the capability and Product responses we call. On buys that include a property list, we also check that the returned Products honour the property list, channels, and countries we sent. Property-list support is a per-buy requirement that is being rolled out; it does not block an Agent. Today, we send a property list only to an Agent that declares support. We may still return Products from an Agent that does not declare it and send that Agent a buy without the list. As feature routing rolls out, a buy that needs a property list will go only to Agents that declare support, while Agents that do not declare it can still receive buys that do not need it. Declare every feature your Agent honours.

Required behaviour

We assess these behaviours over the preceding seven days. A failure in this baseline applies to the Agent as a whole, not to one Product or one use case. Repeated means three or more events within the seven-day window. For this baseline, that applies to stale async handoffs and breaches of the request. Persistent means that the flagged condition appears on three or more separate days within that window.

Async tasks

AdCP 3.1 has no capability field for async tasks. We therefore assess them by behaviour, not declaration. If a request cannot finish in time, return submitted or working with a task handle. Then complete the task, or send a status update, before its deadline through polling or webhook. The responsiveness and async-completion rows above are how we assess that handoff.

What happens when we find a problem

A flag tells you what we observed and how to fix it. A blocker stops new buys for every use case on the Agent. Running buys continue in both cases. This protects buyers from starting another buy while preserving an active buy that needs to complete, report, or be stopped safely. Automated flags and blockers for the behaviour baseline are not live yet. Until they are, our team reviews the evidence from our calls with you. The thresholds on this page remain the standard we use for that review and for the automated checks now being rolled out.

Choose the sandbox account to use for certification

Before live-traffic certification can run its test buys for an Agent source, choose one account that the Sales Agent currently returns from list_accounts as an active sandbox account. The setting uses the same seller-account authorization as other inventory-source changes. It allows a principal acting in a Seller Account, including signed-in seller users, staff switched into the seller account, connected chat assistants acting through MCP OAuth, user-owned API keys, and agent, hosted-runtime, acting-user, or agent-registration contexts when they carry an attributed user. The principal type does not change this seller-account check. Every change must also identify a user for the audit record. Seller-scoped organisation API keys and other machine credentials without an attributed user cannot choose or clear the certification sandbox account. Buyer and parent account contexts are refused by the same seller-account authorization used for other source changes. System credentials and SuperAdmins receive the normal seller-account role bypass, but still need an attributed user to make this change. Callers from another seller tenant cannot access that seller’s Source. Use the REST API at /api/v2/storefront/inventory-sources/{sourceId}/certification-sandbox-account, or by asking a connected chat assistant, which uses save_inventory_source. The certification sandbox account records the specific account used for certification. Before every certification buy, we check that the Sales Agent still reports it as active and sandbox: true. This prevents test buys from being sent to an account that the seller has not explicitly identified as safe for certification. Use POST /api/v2/storefront/inventory-sources/{sourceId}/certification-sandbox-account with { "accountId": "seller-sandbox" }. GET on the same path returns the certification sandbox account, including its verification time and the user who last chose it, plus the sandbox accounts currently reported by the Source. Use DELETE on the same path to clear the certification sandbox account. In v3, call save_inventory_source with the existing Source id and certificationSandboxAccountId, for example { "id": "my-sales-source", "certificationSandboxAccountId": "seller-sandbox" }. Set certificationSandboxAccountId to null to clear the certification sandbox account. Read it back with get({ kind: "inventory_source", id: "my-sales-source", include: ["certificationSandboxAccount"] }). Managed sales-agent sources do not use this setting. Certification uses the certification buyer’s admitted sandbox storefront account instead. The account must be active and marked sandbox: true, and it must match the buyer’s operator and the certification advertiser’s brand. We send the buy and any creative sync through the normal managed path, which resolves the managed sales-agent account when it creates the buy. There is nothing for the seller to choose or clear on a managed source. If there is no matching active sandbox storefront account, certification skips that family with sandbox_buyer_account_missing. This includes an account with the matching operator and brand that is not marked as a sandbox account. For managed certification, name a no-charge test advertiser in your ad server. The certification buyer’s sandbox storefront account is mapped to that advertiser through the normal Buyer Account Mapping decision as an active, dedicated binding. The buy runs on your real serving path; the platform never bills it, and you provide the no-charge test placement. Certification does not use a shared default, an unbound native account, or a not_required binding.

Best practices

These practices are not separate eligibility requirements, but they make an Agent easier to integrate and recover when something fails.

Return AdCP error codes

What it is. Return the applicable AdCP error code whenever an operation fails. Why buyers care. A structured error lets buyer software decide whether to retry, correct the request, or show the buyer the next action. How we measure it. We classify the errors returned by our calls. An error we cannot classify is visible in the behaviour review above.

Return an account ID from sync_accounts

What it is. When sync_accounts creates or confirms an account, return its account_id on that account’s row. Apostra stores the ID and sends account: { account_id } on later get_products and create_media_buy calls for that account, instead of the brand and operator. Keep the ID stable for the life of the account. A response row that names a different brand_id from the one we sent, or reports a failed action, is not taken as the account’s ID. Why buyers care. An ID names exactly one account. If the same brand and operator match more than one account on your side, the brand and operator alone return ACCOUNT_AMBIGUOUS, and the buyer’s discovery or buy fails. How we measure it. We read the account_id from the account rows in your sync_accounts responses, and the account-resolution results of the calls that follow.

Hand off long work quickly

What it is. Return submitted quickly when work needs more time, with a task handle that callers can poll or receive by webhook. Why buyers care. The buyer gets a durable acknowledgement instead of waiting for a request that will exceed the response window. How we measure it. We record the initial response time, task handle, and later task status from our calls.

Declare AdCP channels on every Product

What it is. Every Product declares the AdCP media channels it sells in channels, such as display, olv, ctv, or streaming_audio. A Product that sells different channels through different formats can instead declare applies_to_channels on each format option. A format type on its own, such as a video or audio format, is not a channel, because several channels share a format. Why buyers care. Buyers filter discovery, route proposal requests, and report delivery by channel. A Product with no channel is missing from channel-filtered discovery, and its delivery reports with no channel. How we measure it. We read channels, then applies_to_channels, on the Products returned by our get_products calls. Storefront readiness counts the Products that declare neither (see Diagnostics), your Agent page shows the same count as an advisory note under Catalog Product Quality, and live-path certification skips such a Product with the reason missing_channels rather than certifying it on a guessed channel. When a Product relies on applies_to_channels and only some of its format options declare it, the other formats are skipped with the reason missing_channels:<format_kind>. Today this is a best practice: a missing channel produces a warning and never blocks your Agent. Channels will become required for external Agents’ Products in a later change, announced before it takes effect.

Declare every targeting dimension you honour

What it is. Declare each targeting dimension your Agent and Products will honour, and do not declare dimensions that your upstream system ignores. Why buyers care. Buyers use declarations to choose inventory that can meet their brief. An incomplete declaration excludes compatible buys; an inaccurate one can route a buy that cannot meet its targeting. How we measure it. We compare declared capabilities with the request and Products returned by our discovery and buy calls.

Keep capabilities current

What it is. Update capability, account, and Product declarations whenever the upstream system changes what your Agent can do. Why buyers care. Current declarations prevent a buyer from selecting inventory that has changed, disappeared, or no longer supports a required feature. How we measure it. We use the current responses from our calls and compare them with the behaviour we observe. If the two disagree, the declarations-match- behaviour requirement applies. For the full build and launch path, see Build and launch a Sales Agent.