Optionalcontext_Session/conversation identifier for tracking related operations across multiple task invocations. Managed by the protocol layer to maintain conversational context. Distinct from context (per-request opaque echo, see below).
OptionalcontextOptionaltask_Unique identifier for tracking asynchronous operations. Present when a task requires extended processing time. Used to query task status and retrieve results when complete.
OptionalmessageHuman-readable summary of the task result. Provides natural language explanation of what happened, suitable for display to end users or for AI agent comprehension. Generated by the protocol layer based on the task response.
OptionaltimestampISO 8601 timestamp when the response was generated. Useful for debugging, logging, cache validation, and tracking async operation progress.
OptionalreplayedSet to true when this response was returned from the idempotency cache rather than from a fresh execution. Set to false (or omitted) when the request was executed fresh. Buyers use this to distinguish cached replays from new executions — matters for billing reconciliation, audit logs, state-machine routing (cached state-tracking fields are historical snapshots, not current state — re-read via the resource's read endpoint), and any downstream system that assumes exactly-once event semantics. From 3.1 onward, replayed MAY appear on responses to any request that resolved via the idempotency cache, including read tools — universal idempotency_key (see security.mdx §Idempotency) means the cache holds read responses too.
Optionaladcp_Optionalpush_Optionalgovernance_Governance context token issued by the account's governance agent during check_governance. Buyers attach it to governed purchase requests (media buys, rights acquisitions, signal activations, creative services); sellers persist it and include it on all subsequent governance calls for that action's lifecycle. An account binds to one governance agent (see sync_governance); governance is phased across purchase / modification / delivery, not partitioned across specialist agents, so the envelope carries a single token for the full lifecycle.
Value format: governance agents MUST emit a compact JWS per the AdCP JWS profile (see Security — Signed Governance Context). Sellers MAY verify; sellers that do not verify MUST persist and forward the token unchanged. In 3.1 all sellers MUST verify. Non-JWS values from pre-3.0 governance agents are deprecated.
This is the primary correlation key for audit and reporting across the governance lifecycle.
OptionalpayloadConceptual grouping for the task-specific response data defined by individual task response schemas (e.g., get-products-response.json, create-media-buy-response.json). payload is a documentary construct — it is NOT a required wire field, and its on-the-wire shape depends on transport (see Transport serialization below). Task response schemas declare body fields without wrapping them in a payload object; the wire representation places those body fields per transport convention. On MCP the body fields appear as siblings of envelope fields at the root of the tool response; on A2A they appear inside task.artifacts[0].parts[].DataPart; on REST they appear at the root of the JSON body.
Optionaladcp_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.
Optionaladcp_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.
OptionalproductsArray of matching products
OptionalextensionsBundled platform-extension definitions referenced by any product in products. Keyed by <extension_uri>@<digest> (e.g., https://creative.adcontextprotocol.org/translated/meta/extensions/meta_pixel@sha256:abc...). When present, lets buyers resolve platform_extensions references on product format declarations without a separate fetch. Buyer SDKs cache by URI@digest; subsequent get_products responses MAY omit definitions the buyer already has cached and rely on the digest match. Each value is an extension definition with extends (the canonical concept it extends, e.g., tracking), fields (the schema for additional fields the extension contributes), version, and optional description.
This interface was referenced by undefined's JSON-Schema definition
via the patternProperty "^https?://[^@]+@sha256:[a-f0-9]{64}$".
Canonical concept this extension extends (e.g., tracking, cta_vocabulary, destinations, placement).
JSON Schema fragment declaring the additional fields this extension contributes.
Optionalversion?: stringSemantic version of the extension definition. Distinct from the digest — version is human-readable; digest is the integrity check.
Optionaldescription?: stringOptionalproposalsOptional array of proposed media plans with budget allocations across products. Publishers include proposals when they can provide strategic guidance based on the brief. Proposals are actionable - buyers can refine them via follow-up get_products calls within the same session, or execute them directly via create_media_buy.
OptionalerrorsTask-specific errors and warnings (e.g., product filtering issues)
Optionalproperty_[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent.
Optionalcatalog_Whether the seller filtered results based on the provided catalog. True if the seller matched catalog items against its inventory. Absent or false if no catalog was provided or the seller does not support catalog matching.
Optionalrefinement_Seller's response to each change request in the refine array, matched by position. Each entry acknowledges whether the corresponding ask was applied, partially applied, or unable to be fulfilled. MUST contain the same number of entries in the same order as the request's refine array. Only present when the request used buying_mode: 'refine'. Each entry MUST echo the request entry's scope and — for product and proposal scopes — the matching id field (product_id or proposal_id), so orchestrators can cross-validate alignment.
Echoes scope 'request' from the corresponding refine entry.
'applied': the ask was fulfilled. 'partial': the ask was partially fulfilled — see notes for details. 'unable': the seller could not fulfill the ask — see notes for why.
Optionalnotes?: stringSeller explanation of what was done, what couldn't be done, or why. Recommended when status is 'partial' or 'unable'.
Echoes scope 'product' from the corresponding refine entry.
Echoes product_id from the corresponding refine entry.
'applied': the ask was fulfilled. 'partial': the ask was partially fulfilled — see notes for details. 'unable': the seller could not fulfill the ask — see notes for why.
Optionalnotes?: stringSeller explanation of what was done, what couldn't be done, or why. Recommended when status is 'partial' or 'unable'.
Echoes scope 'proposal' from the corresponding refine entry.
Echoes proposal_id from the corresponding refine entry.
'applied': the ask was fulfilled. 'partial': the ask was partially fulfilled — see notes for details. 'unable': the seller could not fulfill the ask — see notes for why.
Optionalnotes?: stringSeller explanation of what was done, what couldn't be done, or why. Recommended when status is 'partial' or 'unable'.
OptionalincompleteDeclares what the seller could not finish within the buyer's time_budget or due to internal limits. Each entry identifies a scope that is missing or partial. Absent when the response is fully complete.
'products': not all inventory sources were searched. 'pricing': products returned but pricing is absent or unconfirmed. 'forecast': products returned but forecast data is absent. 'proposals': proposals were not generated or are incomplete. 'wholesale_feed': in wholesale mode, full feed enumeration could not complete in the time budget — symmetric with get_signals' 'wholesale_feed' scope so sellers have a precise way to declare wholesale-incomplete on the products surface.
Human-readable explanation of what is missing and why.
Optionalestimated_wait?: DurationHow much additional time would resolve this scope. Allows the buyer to decide whether to retry with a larger time_budget.
Optionalfilter_Optional non-fatal diagnostic block describing how the request's filters narrowed the candidate set. Use this to disambiguate empty/small result lists between 'no inventory matches the brief' and 'a specific filter excluded everything', without breaking the filter-not-fail convention (sellers still silently exclude unmatched products; this block is observability, not error reporting). Sellers MAY populate this when meaningful narrowing occurred; buyers MAY use it for triage UX without depending on its presence. Counts only — products are not enumerated by name to avoid leaking competitive intelligence about adjacent campaigns or seller inventory. total_candidates and excluded_by are independently optional — sellers whose baseline candidate set size is sensitive MAY emit excluded_by without total_candidates, or vice versa.
Optionalsemantics?: "any" | "only" | "approximate"How excluded_by[*].count values are computed across multiple filters. only: counts products that would have been included if not for THIS filter alone (deterministic; the right value for 'which filter killed my result set' triage — recommended when feasible). any: counts products excluded by ANY filter (so multiple filters' counts may overlap and sum to more than total_candidates). approximate: sellers SHOULD use this when their pipeline can't cleanly attribute exclusions to a single filter. Buyers SHOULD inspect semantics before doing arithmetic on counts.
Optionaltotal_candidates?: numberNumber of products the seller considered before applying filters. Baseline for interpreting per-filter exclusion counts. Approximate — sellers MAY return a sampled or capped count when their candidate pool is large. Optional; sellers whose baseline candidate set size is sensitive (revealing market posture or competitive density) MAY omit this while still emitting excluded_by.
Optionalexcluded_by?: {Per-filter exclusion counts, keyed by the filter property name as it appears in the request's filters object (e.g., pricing_currencies, required_metrics, required_vendor_metrics, required_geo_targeting, budget_range). Values are objects carrying count and optional filter-specific detail. Only filters that actually narrowed the set need appear here; absence of a key means that filter did not exclude anything (or was not in the request).
OptionalpaginationOptionalwholesale_Opaque token representing the version of the wholesale product feed state used to compose this response. Sellers that implement conditional-fetch (if_wholesale_feed_version) MUST return this on every wholesale-mode response so buyers can cache and probe later. Buyers MUST treat the value as opaque — no format, no ordering, no inspection. The token is scope-keyed: it describes a version for the cache_scope declared on this response, NOT a global agent version. A buyer caches (cache_scope, wholesale_feed_version) pairs and presents the matching token on the next request. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. See specs/wholesale-feed-webhooks.md for the full cache layering model.
Optionalpricing_Opaque token representing the version of the pricing layer, including product pricing_options and nested signal_targeting_options pricing_options. When the seller supports independent pricing versioning, pricing_version changes when prices move but wholesale_feed_version changes only when structure/metadata moves. Same cache_scope keying as wholesale_feed_version. Sellers not separating these MAY omit pricing_version and use wholesale_feed_version for both.
Optionalcache_Declares whether the wholesale_feed_version and pricing_version on this response describe a universal layer or an account-specific overlay. REQUIRED on every 3.1+ response (the 3.1 schema enforces this — the safety property of the two-layer cache model depends on it). 'public': this response describes the seller's published rate card; the buyer MAY dedupe under (agent, buying_mode, filters, property_list, catalog) without scoping by account. 'account': this response includes account-specific overrides; the buyer MUST cache the version under (agent, buying_mode, filters, property_list, catalog, account_id). When the request did NOT include account, the seller MUST return cache_scope: 'public'. When the request included account, the seller MUST return either: 'public' (this account prices off the public rate card — buyer dedupes) or 'account' (account-specific overrides exist — buyer caches under the account key). Sellers MAY return 'public' on an account-scoped request that previously had overrides — buyers SHOULD interpret this as a downgrade and drop their account-overlay for the (agent, filters, mode) tuple. Without schema-required cache_scope, a seller silently omitting the field on an account-scoped response would cause buyers to mis-key the cache and serve account-overlay payloads to other accounts — the canonical safety invariant of the entire cache layering model. Backward-compatibility note for 3.1 validators: SDKs that validate strictly against the 3.1 schema MUST select the validator based on the server-declared adcp_version (release-precision version negotiation, 3.1). For responses with adcp_version starting 3.0, the 3.1 cache_scope-required constraint MUST be relaxed — pre-3.1 sellers correctly emit no cache_scope and remain conformant to their declared version. This is a tightening within 3.1, not a 3.0 break.
OptionalunchangedPresent and true ONLY on wholesale-mode responses when the request carried if_wholesale_feed_version (and/or if_pricing_version) matching the seller's current version for the buyer's cache_scope, in which case products[] MUST be omitted; wholesale_feed_version (echoed), cache_scope (echoed), and pricing_version (echoed when used) MUST still be present. Buyers receiving unchanged: true MUST NOT mutate their local wholesale product mirror. One shape per state: sellers MUST NOT emit unchanged: false — the absence of the field IS the signal that the response carries products. Two shapes ({ unchanged: false, products: [...] } vs. { products: [...] }) for the same state would let some sellers always emit the field and some never would, creating an inconsistency the wire shouldn't carry.
OptionalsandboxWhen true, this response contains simulated data from sandbox mode.
Optionalext
Response payload for get_products task