Skip to main content
get_products is the canonical product door for buyer agents. Send one AdCP-shaped request to selected storefronts—or all storefronts connected to an advertiser—and receive one bounded canonical page as products[] plus optional sibling proposals[]. Every identity remains qualified by its originating storefront. Interchange can optionally evaluate valid seller proposals before returning them. You supply plain-language operating instructions. A managed model chooses accept, reject, or refine, can attach buyer-owned enrichment, and can rank the accepted cohort across sellers.
AdCP remains a one-buyer-to-one-seller protocol. Interchange is the many-to-one buyer layer: it fans out the canonical request, validates each seller independently, qualifies identities, and returns a bounded aggregate page. Sellers do not see one another or receive an Interchange-specific request.

One protocol request, marketplace scale

The scaling layer does four things without forking the protocol:
  • Bilateral calls stay canonical. Buying mode, brief, filters, proposals, and refine are ordinary AdCP semantics at each seller edge.
  • Identity survives aggregation. sf1: product IDs and sfp1: proposal IDs prevent cross-storefront collisions and round-trip into purchase.
  • Slow sellers do not erase fast sellers. Revisioned replacement snapshots expose completed results while other agents remain pending.
  • Responses stay agent-sized. pagination.max_results bounds candidates; proposal graphs remain whole, and the cursor is frozen only when the execution is complete.
get_products does not stop after the first 10 storefronts or choose a final cohort by response speed. When no storefront selector is supplied (or storefronts: "all_connected" is explicit), Interchange resolves every storefront in the buyer’s eligible discovery scope and queries each backing sales agent once. The first provisional revision contains only sellers that have answered so far, so poll until results_complete: true. Then follow pagination.cursor until has_more: false to consume the complete candidate set. pagination.max_results limits each response page, not the seller fan-out. The legacy Discover Products groupLimit and groupOffset fields do not apply to this surface.
Interchange rejects ambiguous seller-specific controls such as conditional catalog versions on the aggregate surface. Query that seller’s AdCP endpoint directly when you need a seller-specific conditional request.

Choose get_products or Discover Products

Both surfaces share the same seller fan-out implementation. They are different buyer projections, not different integrations. Start with get_products for new agent integrations. Use Discover Products when you need its legacy grouped/session presentation or need to continue an existing discoveryId workflow. Calling both for the same request is normally unnecessary; Discover Products projects the same raw seller snapshot rather than running another ranking implementation.

Surfaces

  • REST: POST /api/v2/buyer/products/query
  • Buyer MCP: get_products
  • Buyer api_call: operation get_products
The purchasable continuation is:
  • REST: POST /api/v2/buyer/media-buys/batch
  • Buyer MCP: create_media_buys
  • Buyer api_call: operation create_media_buys

Retrieval without evaluation

Omit ext.interchange.evaluation to receive valid seller responses without a managed evaluation:
Protocol validation always runs. Malformed seller responses, broken proposal allocations, and invalid identities are rejected before evaluation and do not consume evaluation work.

Evaluate and negotiate proposals

Add evaluation instructions when you want Interchange to remove unsuitable proposals, enrich accepted results, negotiate promising proposals, and optionally rank the accepted cohort before it reaches your agent:
The first evaluation pass is absolute:
  • Accept returns the seller’s unchanged proposal and referenced products, with optional buyer-owned enrichment.
  • Reject suppresses the proposal from the normal result.
  • Refine sends a canonical AdCP refine instruction back to that proposal’s seller, then evaluates the seller’s revised response again.
Interchange never rewrites seller pricing, allocations, availability, or terms. Any changed proposal must come back from the seller. Autonomous refinement is bounded by max_refinement_rounds, repeated-request detection, the request deadline, and max_evaluation_passes. A proposal still requesting refinement at the limit is rejected rather than silently accepted. When ranking is present, a separate comparative pass scores accepted candidates under its optional instructions. The response is ordered by score and includes a rank and rationale. Provisional rankings replace earlier snapshots as sellers settle; the final completed revision is frozen. The platform selects the managed models. This version does not expose provider model names, customer executable code, or a model picker.
ext.interchange.screening remains a deprecated compatibility alias for accept, reject, and refine. It does not enable enrichment or comparative ranking. Do not send screening and evaluation together.

Discover Products compatibility

discover_products is a convenience view over the same seller fan-out and evaluation engine. Passing its optional evaluation field enables the same disposition, enrichment, refinement, and ranking behavior, projected into the Discover response shape. Without evaluation, Discover preserves its existing enrichment, relevance, ordering, and refinement behavior. Existing Discover clients do not need to migrate to keep their current behavior.

Proposals and products

Canonical AdCP proposals reference sibling products through allocation product_id values; they do not duplicate complete product objects. Evaluation resolves that graph automatically. A top-level product that is not allocated by any proposal remains a proposal-less candidate, principally for wholesale catalogs. pagination.max_results bounds the combined number of proposals and proposal-less products. Products referenced by a paged proposal accompany that proposal and do not consume another candidate slot, so the proposal graph is never split across pages. Interchange accepts at most 50 allocated products in one proposal. A response contains at most 100 total proposal and product objects; when complete proposal graphs reach that limit, the page returns fewer proposal candidates and the cursor continues from the next whole proposal. Both IDs are opaque and storefront-qualified:
Pass qualified IDs back unchanged in refine and media-buy creation calls.

Stage or buy the result

The execution_id in the response is also the durable search/refinement record used by create_media_buys. Choose whole proposals and/or proposal-less products from that execution. The operation stages them on a DRAFT campaign—the campaign is the shopping cart and the parent of every media buy. Only proposals in the execution’s durable accepted set can be selected. Run get_products again before purchasing from an older execution that predates that set. Use an existing campaign cart:
Or provide campaign.create with the same required fields as a discovery-mode campaign (advertiserId, name, flightDates, and budget). Interchange creates the DRAFT campaign and returns its ID. Media buys are never standalone, even when the caller did not create a campaign first.
  • mode: "stage" updates the cart and prepares DRAFT media buys without contacting sellers.
  • mode: "execute" performs the same preparation, then sends each resulting buy to its originating storefront through ordinary bilateral AdCP create_media_buy calls.
  • replace: true replaces the cart selection before applying this batch; otherwise selections merge idempotently.
Use mode: "execute" when the selected result can be submitted immediately. When you need to inspect or customize per-buy creatives, dates, pacing, or optimization goals, use mode: "stage", make those changes on the returned DRAFT media buys, then call execute_campaign or repeat create_media_buys with the same campaign and selections using mode: "execute". Execution submits the prepared DRAFT directly; it does not rebuild it from the product query. One marketplace call may reach several sellers, but the seller calls are not one atomic transaction. The response reports mediaBuysExecuted, success, and per-buy errors. Retry the same request after a partial failure; completed buys are not dispatched again. A completed product query accepts only an unchanged retry of its recorded batch. To change the selection after execution, start a new get_products query. See Create media buys from a product query for the complete request and response contract.

Progressive responses

Seller responses arrive independently. Each response is a replacement snapshot:
  • revision increases as sellers settle or a refinement produces a new version;
  • provisional: true means replace your previous displayed result;
  • pending_agents identifies sellers still working;
  • accepted proposals may appear while other sellers remain pending;
  • proposals being refined are withheld;
  • no stable cursor is issued until results_complete: true;
  • storefront_results[].message preserves a seller’s explanation for a successful empty response, including when readiness prevents that storefront from transacting; do not interpret that case as “no matching inventory”;
  • the final cursor binds to the execution, revision, evaluation instructions, and offsets.
Response speed affects which sellers are visible in an early provisional revision, not which sellers are retained in the completed execution. Without comparative ranking, completed products use deterministic storefront-qualified identity ordering; when evaluation.ranking is present, the accepted cohort is ordered by that ranking instead. Poll with the returned execution identity:
Do not append provisional pages. Replace the prior page with the new revision. Evaluation is idempotent by candidate version and instruction fingerprint. Polling an unchanged revision does not rerun or remeter it. A seller’s changed proposal is evaluated as a new candidate version.

Evaluation metadata and cost

The response reports evaluation separately from seller progress:
One Proposal Evaluation Pass evaluates a bounded batch of at most ten candidates. One Comparative Proposal Ranking Pass ranks at most 100 accepted candidates. We measure these value units rather than provider tokens. Both are currently calibrating, so charged_ius remains 0. Retrieval without evaluation reports billing_status: "included". If managed evaluation is unavailable, valid candidates pass through and the evaluation status becomes degraded; an infrastructure failure does not silently reject seller supply. Every pass-through candidate is explicitly marked ext.interchange.evaluation.evaluated: false (with confidence: 0), and the response guidance says so. Check evaluated before treating an accept as a judgment: evaluated: false means your evaluation instructions were not applied to that candidate — re-run the request or apply your own screening before buying on it.