list_products is the side-effect-free entry point to the compact product lifecycle. Each invocation completes synchronously, while account-level wholesale feed webhooks keep long-lived buyer mirrors current without polling. It returns products only—never proposals. Buyers can purchase listed products through buy_products or pass returned product_id values to request_proposals for seller planning.
Request schema: /schemas/3.2.0-beta.0/media-buy/list-products-request.json
brand is an identity-only key. Sellers resolve its canonical manifest from the domain; callers do not send logos, colors, or governance overrides in this request. Catalog ingestion belongs to sync_catalogs; discovery accepts only a compact catalog selection under criteria.catalog.
offer_filters select commercial offers. targeting_overlay instead constrains the inventory or impressions that may deliver, so every returned price and forecast must account for the effective overlay. required_overlay_support asks for targeting dimensions the buyer can select independently on packages later; it does not request one product per metro or guarantee availability for every future value.
When a product can honor the overlay exactly, it does not echo the request. A product that proposes a different executable overlay returns sparse targeting_resolution.modifications; selecting that configured product accepts those disclosed changes.
Response
Every response has an explicitoutcome:
A product page can include continuation and cache state:
if_feed_version. Include if_pricing_version only when if_feed_version is also present:
products:
Availability forecasts are a per-read overlay
For calendar-shaped guaranteed inventory (homepage takeovers, sponsorships),list_products can answer “which dates are open?” directly: pass criteria.offer_filters.availability_horizon and request forecast in fields, and each product’s forecast comes back partitioned into time-dimensioned points carrying availability_status. See Flexible Availability Windows for window semantics.
Availability is volatile — every booking changes it — so it is never part of the versioned feed content:
feed_versioncovers the durable offer definition only. Forecast data (including availability windows) does not participate in feed-version scoping and carries its own freshness via the forecast’sgenerated_atandvalid_until.- A request whose
fieldsincludesforecastMUST NOT be answered withoutcome: "unchanged"— that arm omitsproducts, so it cannot carry the volatile data the buyer explicitly asked for. Sellers return a fulllistedresponse even when the feed token matches. - Wholesale feed webhooks fire on definition and pricing changes, not on booking-state changes. Broadcasting window closures to all subscribers would leak demand signals; buyers who need current availability read it on demand, and buyers who need a guarantee take an inventory hold by finalizing a proposal.
forecast in fields) and availability checks (forecast requested, never conditional). Any availability_status returned is a snapshot bounded by valid_until, never a hold — the buy itself remains the authoritative availability check and fails with PRODUCT_UNAVAILABLE when a window has since closed.
Wholesale feed webhooks
Buyers maintaining a wholesale product mirror registerproduct.* and wholesale_feed.bulk_change subscribers through sync_accounts.accounts[].notification_configs[]. Registration is account-level and durable; push_notification_config on an individual list_products request does not create that subscription.
The normal mirror flow is:
- Call
list_productsto bootstrap the mirror and storefeed_versionpluscache_scope. - Register the durable account subscriber through
sync_accounts. - Apply the webhook’s
canonical_productorcanonical_pricing_optionsreplacement payload directly. - On a gap, call
list_productswith the mirror’s last successfully appliedfeed_version. On an uncertain or bulk-change repair, omit the conditional token and replace the mirror from a complete read.