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.

get_products request — 20 fields, 1 required
FieldTypeRequiredDescription
adcp_versionstringRelease-precision AdCP version (VERSION.RELEASE, e.g.
adcp_major_versionintegerDEPRECATED in favor of adcp_version (release-precision string).
buying_modestringrequiredDeclares buyer intent for this request. One of: brief, wholesale, refine.
briefstringNatural language description of campaign requirements.
refineobject[]Array of change requests for iterating on products and proposals from a previous get_products response.
brandbrand-refBrand reference for product discovery context.
catalogcatalogCatalog of items the buyer wants to promote.
accountaccount-refAccount for product lookup.
preferred_delivery_typesdelivery-type[]Delivery types the buyer prefers, in priority order.
filtersproduct-filtersStructured filters for product discovery
property_listproperty-list-ref[AdCP 3.0] Reference to an externally managed property list.
fieldsstring[]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_budgetobjectMaximum time the buyer will commit to this request.
push_notification_configpush-notification-configOptional webhook configuration for async terminal completion/failure notifications on curated discovery.
paginationpagination-requestCursor-based pagination controls for get_products.
if_wholesale_feed_versionstringOpaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent.
if_pricing_versionstringOpaque pricing_version token from a prior get_products response.
contextcontextOpaque correlation data that is echoed unchanged in responses.
required_policiesstring[]Registry policy IDs that the buyer requires to be enforced for products in this response.
extextExtension 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.

get_products response — 29 fields, 1 required
FieldTypeRequiredDescription
adcp_versionstringRelease-precision AdCP version (VERSION.RELEASE, e.g.
adcp_major_versionintegerDEPRECATED in favor of adcp_version (release-precision string).
context_idstringSession/conversation identifier for tracking related operations across multiple task invocations.
contextcontextOpaque correlation data that is echoed unchanged in responses.
task_idstringUnique identifier for tracking asynchronous operations.
statustask-statusrequiredCurrent task execution state. One of: submitted, working, input-required, completed, canceled, failed, rejected, auth-required, unknown.
messagestringHuman-readable summary of the task result.
timestampstringISO 8601 timestamp when the response was generated.
replayedbooleanSet to true when this response was returned from the idempotency cache rather than from a fresh execution.
adcp_errorerrorTransport-envelope error signal for fatal task failures.
push_notification_configpush-notification-configPush notification configuration for async task updates (A2A and REST protocols).
governance_contextstringGovernance context token issued by the account's governance agent during check_governance.
payloadobjectConceptual grouping for the task-specific response data defined by individual task response schemas (e.g., get-products-response.json, create-media-buy-response.json).
productsproduct[]Array of matching products
extensionsobjectBundled platform-extension definitions referenced by any product in `products`.
proposalsproposal[]Optional array of proposed media plans with budget allocations across products.
errorserror[]Task-specific errors and warnings (e.g., product filtering issues)
property_list_appliedboolean[AdCP 3.0] Indicates whether property_list filtering was applied.
catalog_appliedbooleanWhether the seller filtered results based on the provided catalog.
refinement_appliedobject[]Seller's response to each change request in the refine array, matched by position.
incompleteobject[]Declares what the seller could not finish within the buyer's time_budget or due to internal limits.
filter_diagnosticsobjectOptional non-fatal diagnostic block describing how the request's `filters` narrowed the candidate set.
paginationpagination-responseCursor metadata for paginated get_products responses.
wholesale_feed_versionstringOpaque token representing the version of the wholesale product feed state used to compose this response.
pricing_versionstringOpaque token representing the version of the pricing layer, including product pricing_options and nested signal_targeting_options pricing_options.
cache_scopestringDeclares whether the wholesale_feed_version and pricing_version on this response describe a universal layer or an account-specific overlay. One of: public, account.
unchangedbooleanPresent 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…
sandboxbooleanWhen true, this response contains simulated data from sandbox mode.
extextExtension 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.

Example (javascript) — javascript SDK or CLI call — source
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(', ')}`);
  }
}
Example (python) — python SDK or CLI call — source
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())
Example (bash) — bash SDK or CLI call — source
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

Related