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.
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 originalcreate_media_buy call. The storefront stores that callback configuration separately from the operator-facing payload and uses it when the approval resolves.
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.Authorization: Bearer $SCOPE3_API_KEY.
Task reference
List approvals
GET /media-buy-approvals — the approval queue, newest firstGet an approval
GET /media-buy-approvals/{mediaBuyId} — one queue entryDecide an approval
POST /media-buy-approvals/{mediaBuyId}/decide — approve or rejectRetry forwarding
POST /media-buy-approvals/{mediaBuyId}/retry-forward — re-send an approved buy