The AdCP schema registry
The AdCP schema registry is the set of draft-07 JSON Schema files published per release under dist/schemas/, indexed by two files that disagree: index.json lists schemas by protocol area, manifest.json lists them by tool.
AdCP is the Ad Context Protocol, an open standard for software agents that discover inventory and buy media: a buying agent on one side of the wire, a publisher's or platform's sales agent on the other. Every message they exchange has a JSON Schema file behind it, and the release 3.1.13 tree holds 761 of them.
Schema trees
static/schemas/source/ is what the build reads.
dist/schemas/<version>/ is what it writes, and
dist/schemas/latest.json points at the current stable release, currently
3.1.13. That pointer carries five keys: latest, latest_stable, channel, path and index. The source tree carries a
version stamp of its own, bumped only when a release is cut, so for most of a release cycle it
names a version that shipped weeks earlier.
Two things exist only in the output tree: the dereferenced bundled/ copies, and
manifest.json. Neither is visible when browsing the source tree on GitHub.
index.json and manifest.json
The two registry files describe the same release from different angles, and each omits operations the other carries. The operation list is the union of the two. Where both name the same tool they point at the same request and response schema, so the disagreement is entirely about what each file leaves out. Neither file references the other, and nothing in the build compares them.
| Fact | index.json | manifest.json |
|---|---|---|
| Keyed by | protocol area, each operation pointing at a request and a response schema | tool name |
creative_approval, search_brands, validate_property_delivery | in no task list | present |
context_match, identity_match |
under a trusted-match key called operations, not tasks | absent |
list_creative_formats |
both variants: the media-buy request takes property_id and publisher_domain, the creative request takes account, include_pricing and type | the media-buy pair only |
mutating flag, specialism tags, error_code_policy | no equivalent | present |
| Async response arms, one each for submitted, working and input-required | no equivalent | present |
Nothing at the call site declares which of the two list_creative_formats contracts applies.
That comes from
get_adcp_capabilities, whose supported_protocols array says whether the
agent speaks media_buy or creative. Without that call there is no
fallback check: both request schemas require nothing and set additionalProperties to
true, so the wrong variant validates clean and the fields the receiving agent does
not recognise are discarded without an error.
How a reference resolves
Every cross-file reference in a published release is an absolute, version-pinned URL path. The
tree contains no relative paths. The source tree writes those same references without the
version segment, so a resolver configured against GitHub source and then aimed at a release
fetches paths that do not exist — every reference, not some of them. Resolving a published
reference means mapping the /schemas/<version>/ prefix onto the release directory.
// dist/schemas/3.1.13/media-buy/get-products-request.json
{ "$ref": "/schemas/3.1.13/core/version-envelope.json" }
// -> dist/schemas/3.1.13/core/version-envelope.json
// static/schemas/source/media-buy/get-products-request.json
{ "$ref": "/schemas/core/version-envelope.json" }
// -> static/schemas/source/core/version-envelope.json The shared envelopes
core/version-envelope.json declares two properties, adcp_version and
adcp_major_version, is referenced by 137 files, and requests and responses compose
it alike. core/protocol-envelope.json declares the rest: status,
context_id, task_id, message, timestamp,
payload and the async plumbing. 68 response schemas compose it and no request schema
does, so a response schema inherits those fields before declaring any of its own.
Schemas with no inbound reference
Some files in the release are reachable from neither registry file nor from any $ref. Every file in error-details/ is one, and so is every file in core/async-response-refs/, which holds one copy of each async arm the manifest already names under a different path.
Nothing points at either set, so nothing makes them mandatory.
creative/creative-purged-webhook.json is unreferenced for a different reason: it describes
a payload that arrives out of band, and a webhook body has nothing to $ref it.
Absence from index.json does not imply absence from the reference graph.
formats/canonical/image.json has no entry in the index, and neither do
video_hosted, html5, audio_daast or the other nine files in
that directory. They are reachable two hops down:
core/product-format-declaration.json refs formats/canonical/image.json, which refs formats/canonical/_base.json.
Error detail schemas
enums/error-code.json defines 92 error codes. error-details/ holds 15 schemas,
one per shape those errors can take. No $ref edge joins the two files.
core/error.json is referenced by 67 schemas, more than any of the domain objects it sits
alongside, and it declares details as a bare object of no particular shape, with no $ref and no discriminator. The link between a code and its detail schema lives in an enumDescriptions string, in markdown backticks. For
VERSION_UNSUPPORTED: "The error details SHOULD follow
error-details/version-unsupported.json". Other codes carry a pointer written the
same way. A draft-07 validator applies no constraint from enumDescriptions, so the
pointer has no effect on validation.
The same file carries the structured form of that pattern for a different case. Next to enumDescriptions sits an enumMetadata block whose $comment reads: "SDKs MUST consume this
block instead of parsing 'Recovery: X' from enumDescriptions prose." enumMetadata carries
recovery hints as structured data; the error-detail schema pointers remain in enumDescriptions prose.
Mapping a code to its detail schema is therefore a manual step. enumDescriptions names
six of the fifteen outright. The other nine mappings are stated nowhere; the filename and the code
name correspond by convention only. The map from code to detail schema exists in no release artefact,
so a new code or a changed mapping is not detectable from a release diff.
discriminator under draft-07
42 schemas in the release use discriminator to say which branch of a oneOf applies. discriminator is an OpenAPI keyword, draft-07 does not define it, and a draft-07
validator therefore ignores it and evaluates every branch. Validation outcome is unchanged, because
the nine branches under core/pricing-option.json each pin pricing_model with a const. Error output is not: an invalid pricing_model returns one
failure per branch, nine in place of the single branch failure that was intended. A client that needs
the intended diagnostic selects the branch on pricing_model itself and reports only that
branch's errors.
Bundled schemas
docs/building/by-layer/L0/schemas.mdx directs tools that cannot resolve
$ref to the bundled schemas, which have every reference inlined. That page states that
all request and response task schemas are bundled. The table on the same page names eight bundled/ directories and omits brand/, collection/, account/ and
governance/. The release ships those eight, so the sentence overstates the
coverage.
23 of the 64 operations have no bundle: every brand-protocol operation, every collection-list
operation, every account operation, the four governance plan operations, both serve-time operations
and comply_test_controller. None of the 20 async response arms are bundled either.
An integration built against brand rights or account financials without a
$ref-resolving validator has no offline schema to load for those operations.
The 10 core objects
These are the domain nouns the operations pass around. They are not the schemas that hold the
reference tree together: the most-referenced files in the release are extension, envelope and
error scaffolding.
media_buy_id appears in schemas across the release, while
core/media-buy.json itself is referenced once, because a media buy is fetched by identifier
rather than passed around.
| Schema | Inbound references |
|---|---|
core/ext.json | 238 |
core/context.json | 177 |
core/version-envelope.json | 137 |
core/protocol-envelope.json | 68 |
core/error.json | 67 |
core/media-buy.json | 1 |
product
Represents available advertising inventory
product fields — 49 fields, 7 required
| Field | Type | Required | Description |
|---|---|---|---|
product_id | string | required | Unique identifier for the product |
name | string | required | Human-readable product name |
description | string | required | Detailed description of the product and its inventory |
publisher_properties | any[] | required | SDK implementers MUST enforce singular-only at runtime: each entry uses the singular `publisher_domain` form; the compact `publisher_domains[]` form is rejected on products. |
channels | channels[] | Advertising channels this product is sold as. | |
format_ids | format-id[] | Legacy named-format path: array of supported creative format IDs (structured format_id objects with agent_url and id). | |
format_options | product-format-declaration[] | 3.1+ format-option path: one or more inline format declarations the product accepts. | |
placements | placement[] | Optional array of specific public placements within this product. | |
video_placement_types | video-placement-type[] | Declared video placement types that may be included in this product, using IAB Tech Lab/OpenRTB 2.6 video.plcmt definitions with AdCP-native names. | |
audio_distribution_types | audio-distribution-type[] | Declared audio distribution types that may be included in this product, using IAB Tech Lab/OpenRTB 2.6 audio.feed definitions with AdCP-native names. | |
sponsored_placement_types | sponsored-placement-type[] | Declared sponsored-placement types that may be included in this product, distinguishing where catalog-driven retail-media placements render on the retailer surface (sponsored search, sponsored display, or sponsored nati… | |
social_placement_surfaces | social-placement-surface[] | Declared social-placement surfaces that may be included in this product, distinguishing the in-app surface where social placements render (feed, stories, short_video, explore, or search). | |
delivery_type | delivery-type | required | Type of inventory delivery One of: guaranteed, non_guaranteed. |
exclusivity | exclusivity | Whether this product offers exclusive access to its inventory. One of: none, category, exclusive. | |
pricing_options | pricing-option[] | required | Available pricing models for this product |
forecast | delivery-forecast | Forecasted delivery metrics for this product. | |
outcome_measurement | outcome-measurement | **Deprecated as of this minor.** Outcome capabilities (incremental sales lift, brand lift, foot traffic, etc.) are now declared via `reporting_capabilities.available_metrics` (the same path used for impressions, convers… | |
delivery_measurement | object | Measurement vendors and methodology for delivery metrics. | |
measurement_terms | measurement-terms | Seller's default billing measurement and makegood terms. | |
performance_standards | performance-standard[] | Seller's default performance standards for this product: viewability, IVT, completion rate, brand safety, attention score. | |
cancellation_policy | cancellation-policy | Cancellation terms for this product. | |
allowed_actions | product-allowed-action[] | Actions buyers may perform on buys created against this product, scoped to statuses and modes. | |
reporting_capabilities | reporting-capabilities | required | Reporting capabilities available for a product |
creative_policy | creative-policy | Creative requirements and restrictions for a product | |
is_custom | boolean | Whether this is a custom product | |
property_targeting_allowed | boolean | Whether buyers can filter this product to a subset of its publisher_properties. | |
data_provider_signals | data-provider-signal-selector[] | Deprecated. | |
included_signals | signal-listing[] | Non-selectable signal metadata for signals already included in, bundled with, or planned into this product. | |
signal_targeting_options | product-signal-targeting-option[] | Inline seller-offered signals that may be applied to packages for this product at create_media_buy time. | |
signal_targeting_rules | signal-targeting-rules | Composition rules for selecting signals on this product. | |
signal_targeting_allowed | boolean | Whether this product has a package-level signal_targeting_groups surface. | |
catalog_types | catalog-type[] | Catalog types this product supports for catalog-driven campaigns. | |
metric_optimization | object | Metric optimization capabilities for this product. | |
vendor_metric_optimization | vendor-metric-optimization | Vendor-attested metric optimization capabilities for this product. | |
max_optimization_goals | integer | Maximum number of optimization_goals this product accepts on a package. | |
measurement_readiness | measurement-readiness | Assessment of whether the buyer's event source setup is sufficient for this product to optimize effectively. | |
conversion_tracking | object | Conversion event tracking for this product. | |
catalog_match | object | When the buyer provides a catalog on get_products, indicates which catalog items are eligible for this product. | |
brief_relevance | string | Explanation of why this product matches the brief (only included when brief is provided) | |
expires_at | string | Expiration timestamp. | |
product_card | object | Optional standard visual card for displaying this product in user interfaces (catalog browsers, dashboards, agent UIs). | |
product_card_detailed | object | Optional detailed card with hero + carousel + structured specifications, for rich product presentation (media-kit-style pages, full product detail views). | |
collections | collection-selector[] | Collections available in this product. | |
collection_targeting_allowed | boolean | Whether buyers can target a subset of this product's collections. | |
installments | installment[] | Specific installments included in this product. | |
enforced_policies | string[] | Registry policy IDs the seller enforces for this product. | |
trusted_match | object | Trusted Match Protocol capabilities for this product. | |
material_submission | object | Instructions for submitting physical creative materials (print, static OOH, cinema). | |
ext | ext | Extension object for platform-specific, vendor-namespaced parameters. |
media-buy
Represents a purchased advertising campaign
media-buy fields — 17 fields, 6 required
| Field | Type | Required | Description |
|---|---|---|---|
media_buy_id | string | required | Seller's unique identifier for the media buy |
account | account | Account billed for this media buy | |
status | media-buy-status | required | Status of a media buy. One of: pending_creatives, pending_start, active, paused, completed, rejected, canceled. |
health | object | Aggregate health based on open impairments[]. | |
impairments | impairment[] | Open impairments — upstream dependency state changes that affect delivery for at least one package on this buy. | |
rejection_reason | string | Reason provided by the seller when status is 'rejected'. | |
confirmed_at | string | null | required | ISO 8601 timestamp when the seller committed to this media buy. |
cancellation | object | Cancellation metadata. | |
total_budget | number | required | Total budget amount |
packages | package[] | required | Array of packages within this media buy |
context | context | Opaque media-buy-level correlation data echoed unchanged from the create_media_buy request. | |
invoice_recipient | business-entity | Per-buy override for who receives the invoice. | |
creative_deadline | string | ISO 8601 timestamp for creative upload deadline | |
revision | integer | required | Monotonically increasing optimistic concurrency token. |
created_at | string | Creation timestamp | |
updated_at | string | Last update timestamp | |
ext | ext | Extension object for platform-specific, vendor-namespaced parameters. |
package
A specific product within a media buy (line item)
package fields — 29 fields, 1 required
| Field | Type | Required | Description |
|---|---|---|---|
package_id | string | required | Seller's unique identifier for the package |
product_id | string | ID of the product this package is based on. | |
budget | number | Budget allocation for this package in the currency specified by the pricing option | |
pacing | pacing | Budget pacing strategy One of: even, asap, front_loaded. | |
pricing_option_id | string | ID of the selected pricing option from the product's pricing_options array | |
bid_price | number | Bid price for auction-based pricing. | |
price_breakdown | price-breakdown | Breakdown of the effective price for this package. | |
impressions | number | Impression goal for this package | |
catalogs | catalog[] | Catalogs this package promotes. | |
format_ids | format-id[] | Legacy named-format IDs supplied for this package on create_media_buy. | |
format_option_refs | format-option-ref[] | Structured 3.1+ format option references supplied for this package on create_media_buy. | |
format_kind | canonical-format-kind | Direct canonical selector supplied for this package on create_media_buy. One of: image, html5, display_tag, image_carousel, video_hosted, video_vast, audio_hosted, audio_daast, sponsored_placement, native_in_feed, responsive_creative, agent_placement, custom. | |
params | object | Parameters for the direct canonical selector in `format_kind`, echoed from the create_media_buy request whenever the request included it. | |
targeting_overlay | targeting | Optional restriction overlays for media buys. | |
measurement_terms | measurement-terms | Agreed billing measurement and makegood terms for this package. | |
performance_standards | performance-standard[] | Agreed performance standards for this package. | |
committed_metrics | committed-metric[] | The binding reporting contract for this package — what the seller has agreed to populate in delivery reports. | |
creative_assignments | creative-assignment[] | Creative assets assigned to this package | |
format_ids_to_provide | format-id[] | Format IDs that creative assets will be provided for this package | |
optimization_goals | optimization-goal[] | Optimization targets for this package. | |
start_time | string | Flight start date/time for this package in ISO 8601 format. | |
end_time | string | Flight end date/time for this package in ISO 8601 format. | |
paused | boolean | Whether this package is paused by the buyer. | |
canceled | boolean | Whether this package has been canceled. | |
cancellation | object | Cancellation metadata. | |
agency_estimate_number | string | Agency estimate or authorization number for this package. | |
creative_deadline | string | ISO 8601 timestamp for creative upload or change deadline for this package. | |
context | context | Opaque package-level correlation data echoed unchanged in responses, webhooks, and read surfaces. | |
ext | ext | Extension object for platform-specific, vendor-namespaced parameters. |
creative-asset
Creative asset for upload to library — supports static assets, generative formats, and third-party snippets.
creative-asset fields — 14 fields, 3 required
| Field | Type | Required | Description |
|---|---|---|---|
creative_id | string | required | Unique identifier for the creative. |
name | string | required | Human-readable creative name |
format_id | format-id | Legacy named-format path. | |
format_kind | canonical-format-kind | 3.1+ canonical-format path. One of: image, html5, display_tag, image_carousel, video_hosted, video_vast, audio_hosted, audio_daast, sponsored_placement, native_in_feed, responsive_creative, agent_placement, custom. | |
format_option_ref | format-option-ref | 3.1+ format-option path, optional. | |
assets | object | required | Assets required by the format, keyed by asset_id or canonical asset_group_id. |
inputs | object[] | Preview contexts for generative formats - defines what scenarios to generate previews for | |
tags | string[] | User-defined tags for organization and searchability | |
status | creative-status | For generative creatives: set to 'approved' to finalize, 'rejected' to request regeneration with updated assets/message. One of: processing, pending_review, approved, suspended, rejected, archived. | |
weight | number | Optional delivery weight for creative rotation when uploading via create_media_buy or update_media_buy (0-100). | |
placement_refs | placement-ref[] | Optional structured placement references where this uploaded creative should run when uploading via create_media_buy or update_media_buy. | |
placement_ids | string[] | Legacy shorthand array of placement IDs where this creative should run when uploading via create_media_buy or update_media_buy. | |
industry_identifiers | industry-identifier[] | Industry-standard or market-specific identifiers for this creative (e.g., Ad-ID, ISCI, Clearcast clock number, IDcrea). | |
provenance | provenance | Provenance metadata for this creative. |
targeting
Optional restriction overlays for media buys.
targeting fields — 28 fields, 0 required
| Field | Type | Required | Description |
|---|---|---|---|
geo_countries | string[] | Restrict delivery to specific countries. | |
geo_countries_exclude | string[] | Exclude specific countries from delivery. | |
geo_regions | string[] | Restrict delivery to specific regions/states. | |
geo_regions_exclude | string[] | Exclude specific regions/states from delivery. | |
geo_metros | object[] | Restrict delivery to specific metro areas. | |
geo_metros_exclude | object[] | Exclude specific metro areas from delivery. | |
geo_postal_areas | postal-area[] | Restrict delivery to specific postal areas. | |
geo_postal_areas_exclude | postal-area[] | Exclude specific postal areas from delivery. | |
daypart_targets | daypart-target[] | Restrict delivery to specific time windows. | |
axe_include_segment | string | Deprecated: Use TMP provider fields instead. | |
axe_exclude_segment | string | Deprecated: Use TMP provider fields instead. | |
audience_include | string[] | Restrict delivery to members of these first-party CRM audiences. | |
audience_exclude | string[] | Suppress delivery to members of these first-party CRM audiences. | |
signal_targeting_groups | package-signal-targeting-groups | Basic Boolean grouping for seller-offered signals. | |
signal_targeting | signal-targeting[] | DEPRECATED. | |
frequency_cap | frequency-cap | Frequency capping settings for package-level application. | |
property_list | property-list-ref | Reference to a property list for targeting specific properties within this product. | |
collection_list | collection-list-ref | Reference to a collection list for including specific collections (programs, shows) within this product. | |
collection_list_exclude | collection-list-ref | Reference to a collection list for excluding specific collections (programs, shows) from this product. | |
age_restriction | object | Age restriction for compliance. | |
device_platform | device-platform[] | Restrict to specific platforms. | |
device_type | device-type[] | Restrict to specific device form factors. | |
device_type_exclude | device-type[] | Exclude specific device form factors from delivery (e.g., exclude CTV for app-install campaigns). | |
store_catchments | object[] | Target users within store catchment areas from a synced store catalog. | |
geo_proximity | object[] | Target users within travel time, distance, or a custom boundary around arbitrary geographic points. | |
language | string[] | Restrict to users with specific language preferences. | |
keyword_targets | object[] | Keyword targeting for search and retail media platforms. | |
negative_keywords | object[] | Keywords to exclude from delivery. |
format
Represents a creative format with its requirements
format fields — 20 fields, 2 required
| Field | Type | Required | Description |
|---|---|---|---|
format_id | format-id | required | This format's own identifier — a structured object {agent_url, id}, not a string. |
name | string | required | Human-readable format name |
description | string | Plain text explanation of what this format does and what assets it requires | |
example_url | string | Optional URL to showcase page with examples and interactive demos of this format | |
accepts_parameters | format-id-parameter[] | List of parameters this format accepts in format_id. | |
renders | object[] | Specification of rendered pieces for this format. | |
assets | any[] | Array of all assets supported for this format. | |
delivery | object | Delivery method specifications (e.g., hosted, VAST, third-party tags) | |
supported_macros | any[] | List of universal macros supported by this format (e.g., MEDIA_BUY_ID, CACHEBUSTER, DEVICE_ID). | |
input_format_ids | format-id[] | **DEPRECATED in 3.1. | |
output_format_ids | format-id[] | **DEPRECATED in 3.1. | |
format_card | object | Optional standard visual card (300x400px) for displaying this format in user interfaces. | |
accessibility | object | Accessibility posture of this format. | |
supported_disclosure_positions | disclosure-position[] | Disclosure positions this format can render. | |
disclosure_capabilities | object[] | Structured disclosure capabilities per position with persistence modes. | |
format_card_detailed | object | Optional detailed card with carousel and full specifications. | |
reported_metrics | available-metric[] | Metrics this format can produce in delivery reporting. | |
pricing_options | vendor-pricing-option[] | **DEPRECATED in 3.1. | |
canonical | canonical-projection-ref | Optional v2 canonical-projection annotation. | |
canonical_parameters | product-format-declaration | **DEPRECATED in 3.1. |
pricing-option
A pricing model option offered by a publisher for a product.
A oneOf across the pricing models, discriminated by pricing_model, so it has no flat field list. Merging the branches describes an object that cannot validate.
error
Standard error structure for task-specific errors and warnings
| Field | Type | Required | Description |
|---|---|---|---|
code | string | required | Error code for programmatic handling. |
message | string | required | Human-readable error message |
field | string | Field path associated with the error in JSONPath-lite format (e.g., 'packages[0].targeting'). | |
suggestion | string | Suggested fix for the error | |
retry_after | number | Seconds to wait before retrying the operation. | |
issues | object[] | Structured list of validation failures. | |
details | object | Additional task-specific error details. | |
recovery | string | Agent recovery classification. One of: transient, correctable, terminal. | |
source | string | Who emitted this error entry. One of: producer, sdk. | |
sdk_id | string | Optional identifier for the SDK that augmented this error entry. |
brand-ref
Reference to a brand by domain and optional brand_id.
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain where /.well-known/brand.json is hosted, or the brand's operating domain |
brand_id | brand-id | Brand identifier within the house portfolio. | |
industries | string[] | Inline override for the brand's industries. | |
data_subject_contestation | object | Inline override for the brand's contestation contact point. | |
brand_kit_override | object | Inline override for brand-kit fields normally resolved from `/.well-known/brand.json` on `domain` (logo, colors, voice, tagline). |
account-ref
Reference to an account by seller-assigned ID or natural key.
A oneOf across an account_id form and a brand plus operator natural key, so it has no flat field list. Merging the branches describes an object that cannot validate.
A client author's checklist
-
Read
dist/schemas/<version>/, notstatic/schemas/source/. The two trees write$refdifferently and a resolver tuned for one returns 404 on the other. -
Take the operation list as the union of
index.jsonandmanifest.json, and resolve the schema paths through the index. -
Call
get_adcp_capabilitiesbeforelist_creative_formats. Nothing else identifies which of the two contracts is in force, and neither request schema rejects the wrong payload. -
Resolve
$refin the client rather than loadingbundled/. For 23 of the 64 operations no bundle exists. -
Hold the error-code to
error-details/map, all 15 entries, in client source, and diff it againstenums/error-code.jsonon every release.
Frequently asked
- Where are the AdCP schemas?
- Under dist/schemas/<version>/ in the protocol repository. dist/schemas/latest.json is the pointer, and it carries five keys: latest, latest_stable, channel, path and index. Read whichever release it names. static/schemas/source/ is the build input and ships neither the bundled/ copies nor manifest.json.
- How do AdCP schemas reference each other?
- By absolute, version-pinned URL path, such as /schemas/<version>/media-buy/get-products-request.json. Every reference in a published release includes the version segment and every reference in the source tree omits it, so a resolver written against one tree fetches paths that do not exist in the other.
- Should an AdCP client read index.json or manifest.json?
- Both. index.json resolves the schemas and is the only file carrying both list_creative_formats variants. manifest.json is the only place the mutating flag, the specialism tags, the async response arms and error_code_policy exist. Each names operations the other omits, so the real operation list is the union of the two.
- Does index.json list every AdCP schema in the release?
- No. Some schemas have no index entry and no inbound $ref from anywhere in the release, including every file in error-details/ and every file in core/async-response-refs/. Others are absent from the index but still reachable, such as the canonical format schemas two hops down from core/product-format-declaration.json.