Skip to main content
When a buyer submits a media buy to your storefront, it lands in your approval queue as a pending entry holding the raw AdCP create_media_buy payload. You inspect it and record a decision: approved or rejected. Approved entries are forwarded upstream to the underlying sales agent by the storefront’s MCP layer; the forwardedAt stamp tells you when that succeeded. For when this queue is used — the mediaBuyApproval setting (and why manual still auto-forwards clearly on-policy buys), the lowest-risk “review everything” posture, and how you find out something is waiting — see Reviewing buyer transactions.

What the pre-screen verdict means

Each queued entry carries the deterministic pre-screen verdict: clearly on policy (would have auto-forwarded), needs a look, or clearly against an explicit rule you wrote. That last bucket is decision-support only — the platform does not auto-reject; a clearly-against-policy buy still queues for your decision. For the full verdict model, the one-way AI second opinion, and how the agent reads your written policy, see Acceptance policy.
A buyer you’ve opted into per-buyer auto-approve never appears in this queue — their media buys forward without a pending entry. If you expect a buyer’s buys and never see them here, check your auto-approve overrides.
An entry moves through pending → approved or pending → rejected. Decisions are terminal — deciding an entry that is no longer pending is rejected, so a double-decide cannot slip through. The revoked state covers buyer- or system-initiated cancellation after a decision and is not something you set on the decide endpoint. Each entry is keyed by the buyer’s AdCP mediaBuyId. The portable Approvals Page keeps the decision and its forwarding result separate. If your approval is recorded but delivery to one or more sources is incomplete, it shows a partial-success notice and lets you explicitly confirm a typed retry without leaving the Page. The same idempotency key is reused, so a source that already received the buy cannot create a duplicate booking. A source response that means “accepted and still processing” does not offer a duplicate retry. A forward a source refuses structurally is usually not a dead end. The entry is stamped forwardedAt and the platform stops re-attempting it — re-sending an identical payload to a source that refused it would fail the same way every time. Once the underlying cause is fixed, the API can recover the buy in place: Retry forwarding with forceTerminal re-sends it under the same mediaBuyId with your approval intact, so the buyer does not need to resubmit under a new id. This is an API control; the chat and Pending operations surfaces still offer escalation rather than a retry for these buys. A buy terminalized before any source was contacted because of an unconfigured settlement currency, an expired FX quote, or another permanent prerequisite cannot be recovered this way and must be resubmitted. A storefront intake hold is different: the approved buy remains queued with forwardedAt: null and forwards automatically after intake resumes. Time spent on hold does not use up the forwarding retry window, and the original approval time remains unchanged.

Buyer task callbacks

Buyer agents can attach AdCP push-notification config to the original create_media_buy call. The storefront stores that callback configuration separately from the operator-facing payload and uses it when the approval resolves.
Use push_notification_config for canonical AdCP requests. The storefront also accepts pushNotificationConfig from clients that pass camelCase JSON through a REST/MCP proxy. Callback URLs must be public HTTPS endpoints; localhost, private-network, link-local, metadata, and internal hostnames are rejected. Supported authentication schemes are Bearer and HMAC-SHA256. When the operator approves and every underlying source accepts the forwarded buy, the buyer webhook receives a signed ADCP task event with status: "completed" and a result containing the accepted media_buy_id. When the operator rejects, or approval succeeds but source forwarding fails, the webhook receives status: "failed" with an AdCP-compatible error object. Polling the submitted task remains the fallback if no callback is supplied or delivery fails. Media-buy task events use the AdCP task protocol media-buy; creative approval task events use creative. These webhook protocol values are distinct from the snake-case media_buy value advertised by storefront capabilities.
The approval row returned to storefront operators omits push_notification_config and pushNotificationConfig from submittedPayload so webhook credentials are not exposed in the queue UI or REST responses.
All examples use the storefront base URL:
Authenticate every request with Authorization: Bearer $SCOPE3_API_KEY.

Task reference

List approvals

GET /media-buy-approvals — the approval queue, newest first

Get an approval

GET /media-buy-approvals/{mediaBuyId} — one queue entry

Decide an approval

POST /media-buy-approvals/{mediaBuyId}/decide — approve or reject

Retry forwarding

POST /media-buy-approvals/{mediaBuyId}/retry-forward — re-send an approved buy