Skip to main content
AdCP 3.2 separates reading published offers from asking a seller to build a plan. Start by reading get_adcp_capabilities.media_buy.lifecycle_tools, then choose the path the seller advertises.
Wholesale is a product-feed topology, not a proposal mode. A mirror tracks the seller’s published offers and pricing. Proposal tasks create immutable, seller-authored commercial snapshots for a specific planning conversation.

Both surfaces are optional; neither outranks the other

Sellers choose which discovery surfaces to offer, and lifecycle_tools is the complete statement of that choice. A seller that omits list_products offers no wholesale feed — like a company that quotes through a sales conversation rather than a self-serve signup page. A seller that omits request_proposals sells only published offers. Both are fully conformant; no conformance scenario requires the wholesale path, and the advertised subset carries no implication about inventory breadth or planning capability. The two surfaces serve different buying modes. The wholesale feed is the self-serve, lower-resolution surface: the buyer brings its own intelligence and selects published offers directly, much as it would on an open exchange. A brief through request_proposals is the higher-resolution surface: the seller plans against the buyer’s actual intent. Buyers SHOULD use both surfaces where the seller advertises them. A wholesale feed is a seller’s published-offer subset, not a capability assessment, and buyers SHOULD NOT rank or filter sellers by feed breadth or feed absence. Every product in a feed is a purchasable offer: buy_products transacts it exactly as listed under its feed_version. Sellers demonstrate built-to-brief capability by answering briefs, not by publishing representative products that cannot be bought as listed.

1. Discover the available lifecycle

Do not infer compact-tool support from the protocol version alone. Use the seller’s advertised lifecycle tools:
The field names above use the TypeScript SDK’s normalized capability view. On the wire, inspect media_buy.lifecycle_tools.

2. Express criteria once

Both list_products and request_proposals accept ProductDiscoveryCriteria. Keep three concerns separate:
  • offer_filters select commercial and product characteristics such as channel, delivery type, currency, and reporting support.
  • targeting_overlay contains concrete delivery constraints that must affect the returned product, price, and forecast.
  • required_overlay_support asks for targeting dimensions that the buyer will select later; it is a capability requirement, not a current target value.
Products return canonical format_options[] as their closed accepted creative set. Resolve publisher-backed definitions from adagents.json.formats[]; use a creative agent’s capability IDs to choose production operations.

Published offers and wholesale mirrors

Use list_products when the buyer wants to inspect seller-published offers without asking the seller to author a media plan:
The response contains products only—never proposals—and carries an opaque feed_version. A direct buyer passes that version and selected product terms to buy_products so the seller can reject stale offers instead of silently applying changed terms. A catalog mirror uses the same read as its bootstrap and repair surface. Store feed_version, pricing_version, and cache_scope; subscribe to product.* and wholesale_feed.bulk_change through account notification configuration; then use conditional list_products reads to repair gaps. Do not poll the full feed when the webhook stream is healthy. See list_products wholesale feed webhooks for the complete mirror contract.

Seller-planned proposals

Use request_proposals when the seller should translate a campaign brief into one or more priced plans. Sam Adeyemi at Pinnacle Agency can send the same structured criteria to StreamHaus while keeping strategy in prose:
The seller returns immutable draft proposals. Each revision creates a new proposal_id and preserves its parent:
  1. Use refine_proposals with action: "revise" for typed budget, CPM, flight, product, alternative, or targeting changes.
  2. Verify every returned typed constraint; a partial outcome identifies the exact unsatisfied fields.
  3. Use refine_proposals with action: "finalize" to create a committed, expiring inventory hold.
  4. Call accept_proposal with both the committed proposal_id and terms_digest before expires_at.
Commercial changes after acceptance use the same proposal lineage to create an amendment or negotiated cancellation. Operational changes inside the accepted envelope use control_media_buy. See Proposal negotiation for request shapes, failure planes, finalization, and recovery.

Catalog-driven campaigns

Retail media, travel, job, and other catalog-driven campaigns pass a compact catalog selection in criteria.catalog. The seller matches the buyer-managed catalog to eligible offers; ingest or update the underlying feed separately through sync_catalogs.

Compatibility path

If media_buy.lifecycle_tools is absent, use the established get_products, create_media_buy, and update_media_buy facade documented in the 3.1 → 3.2 migration guide. Keep this branch at the version-adaptation boundary so new planning code works in terms of published offers, proposal snapshots, and revision-checked controls.

Next steps