@adcp/sdk API Reference - v14.3.0
    Preparing search index...

    Interface LegacyGetProductsRequest

    AdCP 3.x compatibility request for discovering and changing advertising products and proposals. Buyers SHOULD express every campaign constraint that has a structured field in that field rather than relying on prose: structured input is cheaper to transmit, deterministic to process, and avoids lossy inference. Exact targeting_overlay values scope returned products, pricing, and forecasts; required_overlay_support identifies targeting dimensions whose values will be supplied on packages later. Explicit hard targeting stated only in a brief remains binding. AdCP 3.2 introduces the narrower list_products, request_proposals, refine_proposals, and decline_proposals tasks; new callers SHOULD use those tasks while existing get_products payloads remain valid throughout 3.x.

    interface LegacyGetProductsRequest {
        adcp_version?: string;
        adcp_major_version?: number;
        idempotency_key?: string;
        buying_mode: "brief" | "wholesale" | "refine";
        brief?: string;
        refine?: (
            | { scope: "request"; ask: string }
            | {
                scope: "product";
                product_id: string;
                action?: "include" | "omit" | "more_like_this";
                ask?: string;
            }
            | {
                scope: "proposal";
                proposal_id: string;
                action?: "include"
                | "omit"
                | "finalize";
                ask?: string;
            }
        )[];
        brand?: BrandReference;
        acceptance_context?: AcceptanceContext;
        catalog?: Catalog;
        account?: AccountReference;
        preferred_delivery_types?: DeliveryType[];
        filters?: ProductFilters;
        targeting_overlay?: TargetingOverlay;
        media_buy_frequency_cap?: {
            suppress?: Duration;
            suppress_minutes?: number;
            max_impressions?: number;
            per?: ReachUnit;
            window?: Duration;
        };
        required_overlay_support?: TargetingOverlayRequirements;
        required_media_buy_support?: ProductMediaBuySupportRequirements;
        property_list?: PropertyListReference;
        fields?: (
            | "name"
            | "identity"
            | "forecast"
            | "description"
            | "publisher_properties"
            | "audience_evidence"
            | "product_id"
            | "channels"
            | "video_placement_types"
            | "audio_distribution_types"
            | "sponsored_placement_types"
            | "social_placement_surfaces"
            | "format_options"
            | "placements"
            | "delivery_type"
            | "exclusivity"
            | "pricing_options"
            | "reporting_capabilities"
            | "measurement_terms"
            | "performance_standards"
            | "catalog_types"
            | "signal_targeting_allowed"
            | "signal_targeting_rules"
            | "demographic_targeting"
            | "overlay_support"
            | "collections"
            | "collection_targeting_allowed"
            | "media_buy_support"
            | "audience_evidence_selections"
            | "max_optimization_goals"
            | "catalog_match"
            | "list_applications"
            | "brief_relevance"
            | "targeting_resolution"
            | "acceptance_policy_profile_ids"
            | "execution_requirements"
            | "expires_at"
            | "allowed_actions"
            | "product_card"
            | "format_ids"
            | "outcome_measurement"
            | "delivery_measurement"
            | "creative_policy"
            | "metric_optimization"
            | "conversion_tracking"
            | "data_provider_signals"
            | "included_signals"
            | "signal_targeting_options"
            | "installments"
            | "is_custom"
            | "product_card_detailed"
            | "enforced_policies"
            | "trusted_match"
        )[];
        time_budget?: Duration;
        push_notification_config?: PushNotificationConfig;
        pagination?: PaginationRequest;
        if_wholesale_feed_version?: string;
        if_pricing_version?: string;
        context?: ContextObject;
        required_policies?: string[];
        ext?: ExtensionObject;
    }
    Index
    adcp_version?: string

    Release-precision AdCP version (VERSION.RELEASE, e.g. "3.0", "3.1", "3.1-beta"). On a request: the buyer's release pin — the seller validates against its supported_versions and returns VERSION_UNSUPPORTED on cross-major mismatch, or downshifts to the highest supported release within the same major. On a response: the release the seller actually served — clients SHOULD validate the response against that release's schema, not against their pin. Patches are not negotiated; surface them as build_version on capabilities for operational visibility. When omitted, falls back to adcp_major_version (deprecated) or server default. Buyers SHOULD emit both adcp_version and adcp_major_version through 3.x to remain compatible with sellers that only read the legacy field. NORMALIZATION: SDKs that read full-semver values from bundle metadata (e.g. ComplianceIndex.published_version = "3.1.0-beta.1") MUST normalize to release-precision ("3.1-beta.1") before emitting on the wire — meta-field values are NOT valid wire values.

    adcp_major_version?: number

    DEPRECATED in favor of adcp_version (release-precision string). Servers MUST continue to honor this field through 3.x. Removed in 4.0. Original semantics: the AdCP major version the buyer's payloads conform to. Sellers validate against their supported major_versions and return VERSION_UNSUPPORTED if unsupported. When omitted, the seller assumes its highest supported version.

    idempotency_key?: string

    Optional client-generated key on the AdCP 3.x compatibility facade. The field remains optional on every arm for wire compatibility. A seller MAY ignore a supplied key on a guaranteed side-effect-free synchronous read. Buyers SHOULD supply a key whenever the request may allocate a task, finalize a proposal, or otherwise change observable state. When a key is supplied on such a request and the seller declares adcp.idempotency.supported: true, the seller MUST apply the AdCP replay contract before that effect. If the key is omitted or the seller declares adcp.idempotency.supported: false, the buyer has no portable at-most-once retry guarantee after an ambiguous result. New callers SHOULD use the compact 3.2 tasks; each stateful split task has its own idempotency identity, so callers MUST retry with the same tool name. Keys MUST be unique per seller and logical request.

    16

    255

    ^[A-Za-z0-9_.:-]{16,255}$

    buying_mode: "brief" | "wholesale" | "refine"

    Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw product inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'. Timing semantics: 'wholesale' is a wholesale product feed read — sellers SHOULD return a synchronous response and MUST NOT route a 'wholesale' request through the async/Submitted arm; partial completion is signalled via the response's incomplete[] field (with optional estimated_wait), not via a task-handoff envelope. 'brief' and 'refine' MAY complete synchronously, or MAY return a Submitted envelope (see get-products-async-response-submitted.json) when curation requires upstream-system queries or HITL review the seller cannot complete inside time_budget. Buyers needing predictable fast wholesale product feed access MUST use 'wholesale'; buyers open to slower curation use 'brief' or 'refine'.

    brief?: string

    Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'. Buyers SHOULD use structured fields for every requirement that can be expressed structurally, and reserve brief prose for goals, context, preferences, and requirements without a structured representation. Sellers MUST apply explicit hard requirements stated in the brief even when the buyer did not duplicate them in a structured field. When a seller translates hard prose into structured targeting that materially affects product eligibility, pricing, or forecasting, it MUST confirm that interpretation once in GetProductsResponse.targeting_resolution.brief_targeting; otherwise confirmation remains a best practice. If hard prose contradicts a structured field, sellers MUST reject the request with INVALID_REQUEST rather than choose one interpretation or return an unexplained empty result.

    refine?: (
        | { scope: "request"; ask: string }
        | {
            scope: "product";
            product_id: string;
            action?: "include" | "omit" | "more_like_this";
            ask?: string;
        }
        | {
            scope: "proposal";
            proposal_id: string;
            action?: "include"
            | "omit"
            | "finalize";
            ask?: string;
        }
    )[]

    Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.

    Finalize-exclusivity rule: if any entry has action: 'finalize', ALL entries in the array MUST be proposal-scoped with action: 'finalize' — mixing finalize entries with include/omit entries or with request- / product-scoped entries MUST be rejected by the seller with INVALID_REQUEST. Finalize is a commit, not a refinement; the buyer expressing intent to commit means refinements have already converged. Buyers needing to refine AND commit in close succession sequence the calls: first a refine call (no finalize), then a finalize call against the resulting proposal_id(s).

    Multi-finalize semantics: multiple finalize entries against different proposal_id values in a single call are allowed and MUST be atomic at the observation point — sellers MUST NOT return a success response unless every named proposal has both completed and been persisted as committed. Pre-commit validation runs before any side-effects (inventory pull, terms lock, governance attestation); if any proposal fails validation, the seller MUST reject the entire call without committing any of the named proposals. There is no rollback operation in the spec — an unfinalize would itself be a new mutation surface; the atomicity guarantee runs entirely on the seller's pre-commit validation gate, not on post-commit reversal. Sellers that cannot guarantee atomic pre-commit validation MUST reject multi-finalize arrays with MULTI_FINALIZE_UNSUPPORTED (preferred — distinguishes seller-side capability gap from a malformed request) or INVALID_REQUEST (acceptable fallback for sellers on a pre-3.1 error catalog). If a mid-commit failure occurs after validation passed but before all proposals persist (e.g., a downstream ad server fails between commits one and two), the seller MUST return INTERNAL_ERROR with refinement_applied[] carrying per-position outcomes — the spec does NOT define a recovery path for this case, and buyers SHOULD treat the resulting state as undefined and re-read via get_media_buys / equivalent before retrying. Buyers MUST NOT assume multi-finalize support without a successful first attempt — there is no capability flag for this; the failure response is the discovery surface. Buyers whose intent specifically requires atomic commit (e.g., budget-shared proposals where one finalizing without the other is incoherent) MUST be prepared to abandon the intent if the seller returns MULTI_FINALIZE_UNSUPPORTED — there is no recovery for that loss of buyer intent beyond sequencing single-finalize calls and accepting the looser commit guarantee.

    Type Declaration

    • { scope: "request"; ask: string }
      • scope: "request"

        Change scoped to the overall request — direction for the selection as a whole.

      • ask: string

        What the buyer is asking for at the request level (e.g., 'more video options and less display', 'suggest how to combine these products').

        1

    • {
          scope: "product";
          product_id: string;
          action?: "include" | "omit" | "more_like_this";
          ask?: string;
      }
      • scope: "product"

        Change scoped to a specific product.

      • product_id: string

        Product ID from a previous get_products response.

        1

      • Optionalaction?: "include" | "omit" | "more_like_this"

        'include' (default): return this product with updated pricing and data. 'omit': exclude this product from the response. 'more_like_this': find additional products similar to this one (the original is also returned). Optional — when omitted, the seller treats the entry as action: 'include'.

      • Optionalask?: string

        What the buyer is asking for on this product. For 'include': specific changes to request (e.g., 'add 16:9 format'). For 'more_like_this': what 'similar' means (e.g., 'same audience but video format'). Ignored when action is 'omit'.

        1

    • {
          scope: "proposal";
          proposal_id: string;
          action?: "include" | "omit" | "finalize";
          ask?: string;
      }
      • scope: "proposal"

        Change scoped to a specific proposal.

      • proposal_id: string

        Proposal ID from a previous get_products response.

        1

      • Optionalaction?: "include" | "omit" | "finalize"

        'include' (default): return this proposal with updated allocations and pricing. 'omit': exclude this proposal from the response. 'finalize': request firm pricing and inventory hold. New callers use refine_proposals with action revise for a draft successor or action finalize for a committed held successor; terminal feedback is available through decline_proposals.

        Legacy finalize is exclusive within the parent refine[] array: see the array-level description for the finalize-exclusivity rule (mixing finalize with non-finalize entries is rejected) and multi-finalize atomicity contract.

      • Optionalask?: string

        What the buyer is asking for on this proposal (e.g., 'shift more budget toward video', 'reduce total by 10%'). Ignored when action is omit.

        1

    acceptance_context?: AcceptanceContext
    catalog?: Catalog
    preferred_delivery_types?: DeliveryType[]

    Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.

    filters?: ProductFilters
    targeting_overlay?: TargetingOverlay
    media_buy_frequency_cap?: {
        suppress?: Duration;
        suppress_minutes?: number;
        max_impressions?: number;
        per?: ReachUnit;
        window?: Duration;
    }

    Type Declaration

    • Optionalsuppress?: Duration

      Cooldown period between consecutive exposures to the same entity. Prevents back-to-back ad delivery (e.g. {"interval": 60, "unit": "minutes"} for a 1-hour cooldown). Preferred over suppress_minutes.

    • Optionalsuppress_minutes?: number

      Deprecated — use suppress instead. Cooldown period in minutes between consecutive exposures to the same entity (e.g. 60 for a 1-hour cooldown).

    • Optionalmax_impressions?: number

      Maximum number of impressions per entity per window. For duration windows, implementations typically use a rolling window. campaign applies across the owning field's full flight: the package flight for a targeting overlay, or the MediaBuy flight for a root cap.

    • Optionalper?: ReachUnit

      Entity granularity for impression counting. Required when max_impressions is set.

    • Optionalwindow?: Duration

      Time window for the max_impressions cap (e.g. {"interval": 7, "unit": "days"} or {"interval": 1, "unit": "campaign"} for the full flight). Required when max_impressions is set.

    required_overlay_support?: TargetingOverlayRequirements
    required_media_buy_support?: ProductMediaBuySupportRequirements
    property_list?: PropertyListReference
    fields?: (
        | "name"
        | "identity"
        | "forecast"
        | "description"
        | "publisher_properties"
        | "audience_evidence"
        | "product_id"
        | "channels"
        | "video_placement_types"
        | "audio_distribution_types"
        | "sponsored_placement_types"
        | "social_placement_surfaces"
        | "format_options"
        | "placements"
        | "delivery_type"
        | "exclusivity"
        | "pricing_options"
        | "reporting_capabilities"
        | "measurement_terms"
        | "performance_standards"
        | "catalog_types"
        | "signal_targeting_allowed"
        | "signal_targeting_rules"
        | "demographic_targeting"
        | "overlay_support"
        | "collections"
        | "collection_targeting_allowed"
        | "media_buy_support"
        | "audience_evidence_selections"
        | "max_optimization_goals"
        | "catalog_match"
        | "list_applications"
        | "brief_relevance"
        | "targeting_resolution"
        | "acceptance_policy_profile_ids"
        | "execution_requirements"
        | "expires_at"
        | "allowed_actions"
        | "product_card"
        | "format_ids"
        | "outcome_measurement"
        | "delivery_measurement"
        | "creative_policy"
        | "metric_optimization"
        | "conversion_tracking"
        | "data_provider_signals"
        | "included_signals"
        | "signal_targeting_options"
        | "installments"
        | "is_custom"
        | "product_card_detailed"
        | "enforced_policies"
        | "trusted_match"
    )[]

    Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed. product_id and name are always included. format_ids is a deprecated 3.x compatibility projection; new integrations request canonical format_options. Safety-critical request-specific fields override projection: Product.targeting_resolution and expires_at MUST be included whenever the seller returns modifications, overlay_support MUST be included when required_overlay_support was requested, media_buy_support MUST be included when required_media_buy_support or media_buy_frequency_cap was requested, list_applications MUST be included when a property or collection list is in the effective targeting, and audience_evidence_selections MUST be included when filters.audience_evidence_requirements affects eligibility or ranking. fields controls the optional audience_evidence payload, not either decision receipt. Response-level brief targeting confirmation is not a projected product field.

    time_budget?: Duration

    Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.

    push_notification_config?: PushNotificationConfig
    pagination?: PaginationRequest
    if_wholesale_feed_version?: string

    Opaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent. Only valid when buying_mode is wholesale. When provided, the seller compares against its current wholesale product feed version for the buyer's cache_scope and MAY return an unchanged: true response (with products omitted) if nothing has changed. The token is scope-keyed: buyers cache (cache_scope, wholesale_feed_version) pairs. Scoping dimensions: (agent, buying_mode, filters, targeting_overlay, media_buy_frequency_cap, required_overlay_support, required_media_buy_support, deprecated property_list, catalog) for cache_scope: 'public'; that tuple plus account identity for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. Backward-compatible: pre-v3.1 agents that ignore this field simply return the full payload, same as the unchanged-server path. See specs/wholesale-feed-webhooks.md for the full sync pattern.

    if_pricing_version?: string

    Opaque pricing_version token from a prior get_products response. MUST only be sent together with if_wholesale_feed_version — pricing version has no structural baseline to compare against on its own. Evaluation order: (1) if_wholesale_feed_version mismatch → seller returns the full payload (pricing is implicitly stale); (2) if_wholesale_feed_version matches but if_pricing_version mismatches → seller returns the full payload so the buyer sees updated pricing_options; (3) both match → seller MAY return unchanged: true. Agents that don't track pricing separately ignore if_pricing_version and fall back to if_wholesale_feed_version semantics. Useful for storefronts that re-price compositions far more often than they re-render product mirrors.

    context?: ContextObject
    required_policies?: string[]

    Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.