Skip to main content

Overview

Building a buyer agent or testing AdCP behavior? Start with Get products across storefronts. It returns a bounded canonical product/proposal page, can query named or all connected storefronts, and optionally screens and refines proposals from buyer instructions. Use the Discover Products compatibility flow below when you need grouped pagination, summary/budget context, browse/SSE, or an existing discoveryId workflow. It projects the same raw fan-out and optional screen; it does not invoke a separate ranking brain.
Product Discovery is the buyer-side loop for finding inventory across one or more sales agents (publishers, exchanges, content owners). You provide a brief — what you’re trying to accomplish, who you’re targeting, when it runs, and how much you can spend — and Scope3 fans the request out to every agent your advertiser has access to. The agents return products and (when supported) recommended proposals that allocate budget across those products. The flow:
1

Connect private storefronts (optional)

For storefronts that gate inventory, register per-source credentials first — see the Storefront object guide.
2

Run discovery

POST /api/v2/buyer/discovery/discover-products with a brief. Returns a discoveryId plus product groups, agent proposals, and budget context.
3

Browse and refine

Page through results with GET /api/v2/buyer/discovery/{id}/discover-products or iterate by sending refine instructions back to the same discoveryId.
4

Pick products or apply a proposal

Add specific products with POST /api/v2/buyer/discovery/{id}/products or apply a full proposal with POST /api/v2/buyer/discovery/{id}/apply-proposal.
5

Promote to a campaign

Call create_media_buys to stage or execute several qualified selections at once. Supply an existing campaign or let the operation create the DRAFT campaign cart. auto-select-products remains available for performance campaigns.
A discovery execution is the long-lived search and refinement record identified by discoveryId or get_products.ext.interchange.execution_id. You can re-open it and refine results without losing context. The DRAFT campaign is the durable shopping cart: it owns selected proposals/products and every media buy. Legacy session-selection endpoints project selections through the same reconciliation path for compatibility.

Progressive delivery

Discovery fans out to many sellers, and they answer at very different speeds — warmed catalogs in milliseconds, live agents in tens of seconds. By default the response waits for everyone (bounded by waitMode/waitSeconds). Pass progressive: true and sellers’ answers arrive as they land instead: the first response returns within a couple of seconds with whoever has answered, resultsComplete: false, and a pendingAgents list; you then poll Browse products with sinceRevision to receive only newly landed seller groups until resultsComplete is true. Every progressive response includes a guidance string spelling out the exact next call, so agent clients need no special handling. The complete worked sequence is in Discover products → Progressive delivery. In Interchange chat, Murph prefers get_products for new canonical product/proposal exploration and uses quick replacement snapshots while sellers answer. Murph uses discover_products when the buyer explicitly asks for the legacy grouped/session presentation or continues an existing discoveryId workflow. It does not call both surfaces by default.

Storefront agents in discovery

Discovery fans out to both third-party sales agents and Scope3 storefront agents. A storefront agent has salesAgentId: "storefront-{platform_id}", where platform_id is the storefront’s public platformId slug, and represents the storefront as a buyer-facing route for product discovery and media-buy execution. That ID identifies the storefront surface; it is not a source ID or underlying source agent ID. Buyers call the same discovery endpoint for all agents. They do not need to distinguish between storefronts that compose products from raw inventory and storefronts that passthrough to an upstream inventory source. Composition storefronts return products assembled from active inventory sources and active operating instructions. Passthrough storefronts proxy get_products to an active source and apply storefront metadata and buyer-instruction overlays before results are returned. Buyer instructions are resolved from operator domain, brand domain, and optional country. Use storefrontIds or storefrontNames when you want to restrict discovery to specific storefronts.
Public buyer discovery only includes Storefronts that have passed marketplace review and are listed. A Storefront can be live for known transactions while it is still pending review, but it will not appear in public discovery results or buyer marketplace browsing until an admin lists it.

Murph account analysis for adapter storefronts

Operators can ask Murph to run analyze_account for adapter-routed storefronts with delegated provider credentials. The tool analyzes a connected advertising account through the storefront adapter and can render an interactive account-analysis viewer in compatible MCP clients. Inputs: The response includes an analysis object returned by the adapter, plus a recommendations[] array for the operator. Adapter implementations may include findings, metrics, account health signals, and other provider-specific details inside analysis. analyze_account is read-only but requires the storefront to be adapter-routed and connected with delegated provider auth. Without a stored delegated credential, Murph returns an auth-required response that includes the provider OAuth setup path. Cross-account targeting is restricted to SuperAdmins; normal storefront operators can analyze only their own storefront.

Public vs private storefronts

Storefronts fall into two visibility tiers: Public discovery is also gated by marketplace review: pending-review and hidden Storefronts are omitted from public buyer discovery even if they are otherwise live. Private storefronts gate inventory behind per-source authentication. Scope3 speaks to all sources - public and private - over the Ad Context Protocol (ADCP); the difference is just whether the source requires the buyer to present credentials before products are returned. The buyer never needs an AAO key directly: AAO registry and compliance signals are handled server-side by Scope3.

Step 1: Connect private storefronts (optional)

If you only need public inventory, skip ahead to Step 2. To unlock private storefronts, register credentials for the relevant inventory source. Three auth types are supported (API key, OAuth, JWT) — the source declares which it requires. Full walkthrough lives in the Storefront object guide; the short version:
For OAuth-secured sources, request an authorize URL and complete the buyer consent flow — Scope3 hosts the callback at /api/v2/storefront/oauth/callback so AI agents and back-end clients don’t need to handle redirects themselves.
Once credentials are registered for a source, every discovery call from your account automatically queries it — no per-call configuration needed.

Step 2: Run discovery

POST /api/v2/buyer/discovery/discover-products is the main entry point. You can pass a brief inline or seed the request from an existing campaign with campaignId.

Request

Response

The first call always creates a new session unless you pass discoveryId. Persist the returned discoveryId — every subsequent call references it.
Discovery fans out across all reachable agents in parallel. Slow agents do not block fast ones; agents that fail or are skipped are surfaced under agentResults only when you pass debug: true.Agents whose advertised channel coverage does not overlap with the requested channels are skipped before fanout (no round-trip), and appear in agentResults with a skipReason like Agent does not sell requested channels (supports: display, ctv; requested: social). For agents that respond with an error, skipReason carries the human-readable rejection text from the agent (e.g. "We do not support the list of channels you specified"); prefer it over error when surfacing the reason in a UI. skipReason is agent-controlled content, sanitize before rendering as HTML.
Sellers operating third-party sales-agent inventory sources can inspect the source-side view in Diagnose third-party sales agents.

Step 3: Page through results

Use the GET endpoint to browse the same session without spending another LLM-enriched discovery call. Filters narrow the cached result set in place.
Query parameters mirror the discover request: groupLimit, groupOffset, productsPerGroup, productOffset, publisherDomain, pricingModel, storefrontIds, storefrontNames, debug.

Refining results

Iterate on a previous response by sending refine instructions back to the same discoveryId. Refinements come in three scopes:
The agent’s reply to each instruction comes back under refinementApplied (matched by position) with status: "applied" | "partial" | "unable" and an optional explanation. You can include screening on the same request. Interchange first applies the explicit seller refinement, then runs the refined proposals through the same managed screening and bounded autonomous-refinement loop used by multi-storefront get_products. Discover returns the accepted snapshot in its existing grouped response shape. Screened Discover calls are terminal; use buyer get_products when you need progressive screened replacement pages while sellers are still responding. A proposal-scoped finalize asks the seller to commit the draft plan: the seller re-validates that every product in the proposal is still available at current pricing, then answers status: "applied" with the commitment window (the committed proposal’s expires_at). A committed proposal is a price and composition commitment — not an inventory hold — and can be executed directly by passing its proposal_id and a total_budget to create_media_buy before it expires. Each committed proposal executes at most once; a proposal whose products have changed since the draft answers status: "unable" with the reason, and you can re-run discovery for a fresh plan.

Step 4: View specific products

Add products you want to evaluate to the session. Each selection records the productId, the salesAgentId it came from, and the group it was discovered in. Optionally pin a budget allocation, pricing option, or bid.
For non-fixed pricing, include bidPrice (read it from the product’s pricingOptions[].rate or floorPrice in the discovery response). List the current session selection at any time:
Pull a single product’s full detail (including extended specs from the sales agent) with the per-product detail endpoint:
Remove products you no longer want:

Step 5: Apply a proposal

When an agent returns a proposal, you can accept its full allocation in one call instead of adding products one at a time.
The response echoes the applied proposal, the budget actually distributed, the products that were added, and any products from the proposal that could not be matched back to the discovery results (productsSkipped).
productsSkipped is non-empty when an agent’s proposal references a product that has aged out of the cached discovery results. Re-run discover to refresh the session, then re-apply.

Auto-select on a campaign

For agentic / hands-off flows, attach an existing campaign and let Scope3 pick products for you. This wraps discovery + selection in a single call against the campaign’s existing brief, flight dates, and budget.
The body is optional — omit it for a fully automated first pass. To iterate, send back the same refine directives accepted by discover-products:
The response includes the underlying discoveryId so you can drop into the manual flow at any point to inspect or adjust the selection.

Best practices

  • Lead with the outcome, not just the demographic. Agents score against campaign objective + creative + audience together.
  • Include guardrails that matter: brand-safety needs, format constraints (16:9, :30s), exclusions.
  • Keep briefs under ~500 characters when possible — long briefs are auto-summarized for LLM enrichment but lose nuance.