AdCP 3.1.13 · Media Buy
get_products
get_products is an operation in the Media Buy area of AdCP 3.1.13. get_products task — discover advertising inventory in AdCP using natural language campaign briefs or structured filters.
get_products request fields
The required column reflects the top-level required array only. One of the 20 request fields carries a top-level required flag: buying_mode. A top-level if, anyOf, oneOf or dependencies block can make an unmarked field mandatory in the mode being called, and a flat table cannot render
a rule that fires in one mode only. Those branches are visible in the request schema itself.
| Field | Type | Required | Description |
|---|---|---|---|
adcp_version | string | Release-precision AdCP version (VERSION.RELEASE, e.g. | |
adcp_major_version | integer | DEPRECATED in favor of adcp_version (release-precision string). | |
buying_mode | string | required | Declares buyer intent for this request. One of: brief, wholesale, refine. |
brief | string | Natural language description of campaign requirements. | |
refine | object[] | Array of change requests for iterating on products and proposals from a previous get_products response. | |
brand | brand-ref | Brand reference for product discovery context. | |
catalog | catalog | Catalog of items the buyer wants to promote. | |
account | account-ref | Account for product lookup. | |
preferred_delivery_types | delivery-type[] | Delivery types the buyer prefers, in priority order. | |
filters | product-filters | Structured filters for product discovery | |
property_list | property-list-ref | [AdCP 3.0] Reference to an externally managed property list. | |
fields | string[] | Specific product fields to include in the response. One of: product_id, name, description, publisher_properties, channels, video_placement_types, audio_distribution_types, sponsored_placement_types, social_placement_surfaces, format_ids, format_options, placements, delivery_type, exclusivity, pricing_options, forecast, outcome_measurement, delivery_measurement, reporting_capabilities, creative_policy, catalog_types, metric_optimization, conversion_tracking, data_provider_signals. | |
time_budget | object | Maximum time the buyer will commit to this request. | |
push_notification_config | push-notification-config | Optional webhook configuration for async terminal completion/failure notifications on curated discovery. | |
pagination | pagination-request | Cursor-based pagination controls for get_products. | |
if_wholesale_feed_version | string | Opaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent. | |
if_pricing_version | string | Opaque pricing_version token from a prior get_products response. | |
context | context | Opaque correlation data that is echoed unchanged in responses. | |
required_policies | string[] | Registry policy IDs that the buyer requires to be enforced for products in this response. | |
ext | ext | Extension object for platform-specific, vendor-namespaced parameters. |
get_products reads. 30 of the 64 registered operations are flagged x-mutates-state and its request schema is not one of them, so repeating the call is side-effect free. AdCP's release notes describe x-mutates-state as a non-normative tooling
hint that agents do not validate, so it is the registry's classification of the operation rather than
a contract, and it is the only machine-readable answer in the registry to whether an operation is
safe to retry.
get_products response fields
The first 13 rows are the shared protocol envelope from core/version-envelope.json and core/protocol-envelope.json. Only 16 of the 29 rows below belong to get_products itself, beginning with products, extensions and proposals. One field in the whole response is marked required: status.
| Field | Type | Required | Description |
|---|---|---|---|
adcp_version | string | Release-precision AdCP version (VERSION.RELEASE, e.g. | |
adcp_major_version | integer | DEPRECATED in favor of adcp_version (release-precision string). | |
context_id | string | Session/conversation identifier for tracking related operations across multiple task invocations. | |
context | context | Opaque correlation data that is echoed unchanged in responses. | |
task_id | string | Unique identifier for tracking asynchronous operations. | |
status | task-status | required | Current task execution state. One of: submitted, working, input-required, completed, canceled, failed, rejected, auth-required, unknown. |
message | string | Human-readable summary of the task result. | |
timestamp | string | ISO 8601 timestamp when the response was generated. | |
replayed | boolean | Set to true when this response was returned from the idempotency cache rather than from a fresh execution. | |
adcp_error | error | Transport-envelope error signal for fatal task failures. | |
push_notification_config | push-notification-config | Push notification configuration for async task updates (A2A and REST protocols). | |
governance_context | string | Governance context token issued by the account's governance agent during check_governance. | |
payload | object | Conceptual grouping for the task-specific response data defined by individual task response schemas (e.g., get-products-response.json, create-media-buy-response.json). | |
products | product[] | Array of matching products | |
extensions | object | Bundled platform-extension definitions referenced by any product in `products`. | |
proposals | proposal[] | Optional array of proposed media plans with budget allocations across products. | |
errors | error[] | Task-specific errors and warnings (e.g., product filtering issues) | |
property_list_applied | boolean | [AdCP 3.0] Indicates whether property_list filtering was applied. | |
catalog_applied | boolean | Whether the seller filtered results based on the provided catalog. | |
refinement_applied | object[] | Seller's response to each change request in the refine array, matched by position. | |
incomplete | object[] | Declares what the seller could not finish within the buyer's time_budget or due to internal limits. | |
filter_diagnostics | object | Optional non-fatal diagnostic block describing how the request's `filters` narrowed the candidate set. | |
pagination | pagination-response | Cursor metadata for paginated get_products responses. | |
wholesale_feed_version | string | Opaque token representing the version of the wholesale product feed state used to compose this response. | |
pricing_version | string | Opaque token representing the version of the pricing layer, including product pricing_options and nested signal_targeting_options pricing_options. | |
cache_scope | string | Declares whether the wholesale_feed_version and pricing_version on this response describe a universal layer or an account-specific overlay. One of: public, account. | |
unchanged | boolean | Present 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 product… | |
sandbox | boolean | When true, this response contains simulated data from sandbox mode. | |
ext | ext | Extension object for platform-specific, vendor-namespaced parameters. |
The shared protocol envelope
62 of AdCP's 64 registered operations carry every one of the 13 envelope fields. report_plan_outcome and check_governance compose core/version-envelope.json only, so they carry the version pair and none of the task fields.
status resolves to enums/task-status.json, which admits nine values:
submitted, working, input-required, completed, canceled, failed, rejected, auth-required,
unknown. The envelope marks it required on every response, and a synchronous call emits completed rather than omitting it. When it returns submitted or working instead, task_id is the
polling handle and
push_notification_config is the webhook the agent echoes back to confirm the callback.
Webhooks are A2A and REST only: MCP sends progress notifications and defines no webhook.
payload appears in the response field table typed object. core/protocol-envelope.json describes it as a documentary construct and states that it is not a required wire field. Body fields
are siblings of the envelope fields: on MCP at the root of the tool response, on A2A in task.artifacts[0].parts[].DataPart, on REST at the root of the JSON body. An accessor that reads response.payload finds
nothing there.
Field lists are not published over the wire
AdCP's integration guide, docs/protocol/calling-an-agent.mdx, states that its MCP
servers no longer publish per-tool parameter schemas: a tools/list call returns an empty
properties object for every tool, and the guide directs clients not to infer shape from it. A client
author reads the schema registry instead of the tool list.
Example get_products calls
The field tables above come from the 3.1.13 schema release and these blocks come from the documentation tree, which is versioned separately, so the two can disagree.
import { testAgent } from '@adcp/sdk/testing';
import { GetProductsResponseSchema } from '@adcp/sdk';
const result = await testAgent.getProducts({
buying_mode: 'brief',
brief: 'Premium athletic footwear with innovative cushioning',
brand: {
domain: 'acmecorp.com'
}
});
if (!result.success) {
throw new Error(`Request failed: ${result.error}`);
}
// Validate response against schema
const validated = GetProductsResponseSchema.parse(result.data);
if (validated.status === 'rejected') {
console.log(`Seller declined the brief: ${validated.reason}`);
for (const suggestion of validated.suggestions ?? []) {
console.log(`- ${suggestion}`);
}
} else {
console.log(`Found ${validated.products.length} products`);
// Access validated product fields
for (const product of validated.products) {
console.log(`- ${product.name} (${product.delivery_type})`);
console.log(` Formats: ${product.format_options.map(option => option.format_kind).join(', ')}`);
}
} import asyncio
from adcp.testing import test_agent
async def discover_products():
result = await test_agent.simple.get_products(
buying_mode='brief',
brief='Premium athletic footwear with innovative cushioning',
brand={
'domain': 'acmecorp.com'
}
)
if result.status == 'rejected':
print(f"Seller declined the brief: {result.reason}")
for suggestion in result.suggestions or []:
print(f"- {suggestion}")
else:
print(f"Found {len(result.products)} products")
asyncio.run(discover_products()) uvx adcp \
https://test-agent.adcontextprotocol.org/sales/mcp \
get_products \
'{"buying_mode":"brief","brief":"Premium athletic footwear with innovative cushioning","brand":{"domain":"acmecorp.com"}}' \
--auth $ADCP_AUTH_TOKEN Frequently asked
- What does get_products do?
- get_products task — discover advertising inventory in AdCP using natural language campaign briefs or structured filters.
- Which fields does a get_products request require?
- One of the 20 request fields carries a top-level required flag: buying_mode. AdCP also constrains requests with top-level if/then, anyOf, oneOf and dependencies blocks that no required array captures, so an unmarked field can still be mandatory in the mode being called.
- Which AdCP version do these get_products field tables describe?
- AdCP 3.1.13, the current published release, last updated 2026-08-11. The documentation tree is versioned separately from the schema tree in the same repository, so a doc page and a schema file can describe the same field differently.
Other operations in Media Buy
-
create_media_buy -
get_media_buy_delivery -
get_media_buys -
list_creative_formats -
log_event -
provide_performance_feedback -
sync_audiences -
sync_catalogs -
sync_event_sources -
update_media_buy