accept_proposal is the single terminal action for the compact proposal lifecycle. It accepts exactly one committed immutable proposal snapshot.
committed retains the AdCP 3.1 reservation guarantee: the seller has locked the proposal’s commercial terms and reserved its inventory until expires_at. Finalization creates that hold; acceptance consumes it and creates, amends, or cancels the MediaBuy.
Depending on proposal_kind, acceptance:
- creates a new MediaBuy;
- applies an amendment to an existing MediaBuy; or
- applies a negotiated cancellation.
/schemas/3.0.28/media-buy/accept-proposal-request.json
total_budget. Acceptance may also set a hard aggregate daily_budget_cap and optional shared budget_cap_timezone; these constrain execution without changing negotiated pricing. If the proposal carries a signature-required insertion order, include io_acceptance.
If the proposal belongs to an opportunity, acceptance closes that planning cycle with accepted_with_seller; callers may repeat the matching opportunity ID explicitly, while the accepted proposal retains the association.
Success returns the resulting MediaBuy identity, the proposal with proposal_status: "accepted", and purchase_bindings[] mapping proposal purchase positions to package IDs for later creative assignment. Acceptance is idempotent. The seller atomically verifies proposal_id, proposal_terms_digest, expiry, and any base_media_buy_revision; stale or mismatched acceptance never applies different terms.
The optional name is buyer-authored MediaBuy display metadata, not a
commercial proposal term. A supplied request value wins over proposal.name,
is persisted unchanged, and is echoed outside accepted_proposal; it is not
covered by proposal_terms_digest or the accepted snapshot’s terms_digest.
When an acceptance creates a MediaBuy and the request omits name, the seller
may seed it from proposal.name only when that value already satisfies the
MediaBuy constraints: non-whitespace and no longer than 255 characters. The
seller must not silently truncate or rewrite a proposal name to make it fit. A
seeded name is then persisted and reported like any other name.
To receive scheduled reports, a reporting_webhook registered on this task needs a buyer-supplied operation_id (see Reporting webhooks); sellers MUST NOT send media_buy_delivery reports to a registration that omits it.
A completed acceptance MAY include warnings[] for non-blocking observations at the commitment boundary. Each warning identifies its package through the returned media_buy_id and purchase_bindings[].package_id; a continuing condition is also readable as an indicator through get_media_buys. The seller may instead return input-required before consuming the proposal. Warnings never appear on failed or submitted arms.
An unexpired committed proposal cannot be rejected merely because its reserved inventory was sold elsewhere. Once expires_at passes, the hold lapses and the seller returns PROPOSAL_EXPIRED; the buyer must request and finalize a fresh proposal.
Definition pins
Before mutating any state, the seller re-resolves every entry in the proposal’scommercial_terms.definition_pins[] and compares its current digest with the pin’s content_digest (see Definition pins). The proposal ID and proposal_terms_digest can verify while a published definition has changed, because terms_digest covers the pin and not the definition it names. A failing pin returns REFERENCE_DEFINITION_CHANGED with no MediaBuy created or amended, one error per drifted pin in errors[]. Each error looks like this:
refine_proposals to obtain fresh pins, reviews the changed definition, and finalizes again. A definition withdrawn from a successfully fetched document is changed and omits current_content_digest; a document that cannot be fetched or parsed is transient, so the seller returns SERVICE_UNAVAILABLE without mutating state. An idempotent replay of an acceptance that already completed returns the stored result without re-verifying pins.