Skip to main content

Documentation Index

Fetch the complete documentation index at: https://agenticadvertisingorg-changeset-release-main.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

AdCP schemas carry several x- prefixed annotation keywords that supplement the JSON Schema vocabulary. JSON Schema validators ignore unknown x- keywords per draft-07 §6, so adding these keys is wire-compatible with any conforming validator. This page is the canonical reference for those annotations. Codegen consumers (TypeScript / Python / Go type generators), the storyboard runner, and the AdCP SDK family read these annotations programmatically; verifiers MAY read them but the normative behavior they describe is also documented in the relevant section of security.mdx or the field’s own description.

x-status

Marks a schema or property as experimental — part of the core protocol but not yet frozen. Sellers implementing experimental surfaces declare the feature id in experimental_features on get_adcp_capabilities. See Experimental Status for the full graduation policy.
"trusted_match": {
  "type": "object",
  "x-status": "experimental",
  "description": "Trusted Match Protocol support..."
}
Allowed values: "experimental". The keyword is omitted on stable surfaces.

x-adcp-validation

Lifts structured normative constraints out of prose descriptions into a machine-readable shape. Storyboard runners and SDK validators consume the structured rules; codegen consumers can ignore the annotation and read the human description. The keyword is most useful for fields whose description currently carries a “MUST be present when…” or “MUST equal the host of…” clause that the storyboard runner cannot enforce by parsing English.

Shape

"some_field": {
  "type": "string",
  "format": "uri",
  "description": "Brief one or two sentences for codegen JSDoc; full constraints live in x-adcp-validation and the linked spec.",
  "x-adcp-validation": {
    "trust_root": true,
    "required_when": { "any_of": [ ... ] },
    "schema_required_when": { ... },
    "verifier_constraints": { ... },
    "distinct_from": "other.field.path",
    "spec": "docs/.../section.mdx#anchor"
  }
}

Sub-keys

KeyTypePurpose
trust_rootbooleanField is load-bearing for signature verification; verifiers MUST treat as authoritative.
required_whenobject wrapping any_of / all_ofStoryboard-enforced required-when rules (3.x). The object has exactly one of any_of (OR-joined) or all_of (AND-joined), each containing an array of leaf conditions. Each leaf is one of: { "field": "...", "non_empty": true }, { "field": "...", "equals": <value> }, { "field": "...", "any_subfield_present": true }. The wrapping object mirrors JSON Schema’s anyOf/allOf precedent so tooling readers can reuse familiar boolean-combinator semantics. Bare arrays are NOT accepted — always wrap.
schema_required_whenconditionWhen the rule promotes from storyboard-enforced to schema-required. Typically keyed on adcp.supported_versions matching a version pattern via any_item_matches_pattern (e.g., "^4\\." for the 4.0 cutover and any 4.x patch).
forbidden_whenobject wrapping any_of / all_ofInverse of required_when. The field MUST be absent (or false/empty, depending on type) when the wrapped condition holds. Same leaf shape as required_when. Use for fields whose presence is mutually exclusive with another posture.
disjoint_withstring (dotted path) or array of dotted pathsItem-level mutual exclusion: no value in this field’s array MAY appear in any of the named arrays. Storyboard runners assert set-disjointness on each. Example: request_signing.warn_for carries disjoint_with: "request_signing.required_for" because an operation can be in one or the other, never both.
subset_ofstring (dotted path)Item-level subset constraint: every value in this field’s array MUST also appear in the named array. Example: request_signing.required_for carries subset_of: "request_signing.supported_for" — an operation can’t be required without being supported.
verifier_constraintsobjectFree-form key-value map of verifier-side rules that don’t fit the structured sub-keys above. Keys are normative (e.g., agent_url_match: "byte_equal"); the storyboard runner enforces these against test vectors. Prefer the structured sub-keys (required_when, forbidden_when, disjoint_with, subset_of) when they fit; reach for verifier_constraints only for one-off rules that don’t generalize.
distinct_fromstring (dotted path)Names another field that has a similar shape but different semantics, to defuse name confusion (e.g., identity.brand_json_url distinct from sponsored_intelligence.brand_url). Verifiers MUST NOT substitute one for the other.
specstring (relative path with anchor)Pointer to the normative section in the docs that defines the field’s full semantics. Always required when other sub-keys are present.

Conformance

  • Validators MUST ignore unknown sub-keys for forward-compatibility (the schema may add new entries in a minor release).
  • The storyboard runner consumes required_when, schema_required_when, and verifier_constraints to generate test cases per release; runners that don’t yet recognize a sub-key MUST skip it and emit an “unrecognized validation rule” warning.
  • Codegen consumers (TypeScript / Python / Go type generators) MAY surface x-adcp-validation.spec as a @see JSDoc link but otherwise treat the annotation as opaque.

Current usage

Representative usage:
FieldSub-keys usedRule
identity.brand_json_urltrust_root, required_when, schema_required_when, verifier_constraints, distinct_fromTrust-root pointer for signing-key discovery; required-when tied to signing posture; schema-required in 4.0; distinct from sponsored_intelligence.brand_url. See security.mdx §Discovering an agent’s signing keys.
identity.key_originsverifier_constraints (purpose_anchoring)Every purpose listed MUST have a corresponding signing posture declared elsewhere on the response. Cross-field rule. See security.mdx §Origin separation.
request_signing.required_forsubset_ofEvery operation listed MUST also appear in supported_for — an operation can’t be required without being supported.
request_signing.warn_fordisjoint_with, subset_ofAn operation MUST NOT appear in both warn_for and required_for. Every operation listed MUST also appear in supported_for.
webhook_signing.supportedverifier_constraints (must_equal_when)When the seller advertises mutating-webhook emission (media_buy.reporting_delivery_methods includes webhook OR media_buy.content_standards.supports_webhook_delivery: true), supported MUST be true. Closes a downgrade vector.
wholesale_feed_webhooks.event_typesverifier_constraints (wholesale_feed_webhook_capability_consistency)product.* event types require wholesale get_products; signal.* event types require wholesale get_signals; wholesale_feed.bulk_change requires at least one declared wholesale repair path and must name only a repairable feed family.
get_products.wholesale_feed_version / get_signals.wholesale_feed_versionverifier_constraints (required_for_wholesale_request)Version tokens are required on wholesale read responses, but the shared response schemas cannot infer the request’s buying_mode / discovery_mode from the response body alone.
Already enforced natively by JSON Schema and excluded from migration:
  • adcp.idempotency — the discriminated oneOf already requires replay_ttl_seconds in the supported branch and forbids it in the unsupported branch.
  • webhook_signing.algorithms — the enum: ["ed25519", "ecdsa-p256-sha256"] on each item already enforces the allowlist.
Migration history tracked at adcontextprotocol/adcp#3827.

x-adcp-hoist

Build-time directive that marks a source schema as a canonically shared type. The schema bundler hoists every inline occurrence into a single root $defs entry and replaces inline copies with $ref pointers; the directive itself is stripped from bundled output. Wire-irrelevant — validators MUST ignore it (draft-07 §6 unknown-keyword semantics) and conforming consumers SHOULD NOT observe it on bundled artifacts.
{
  "$id": "/schemas/core/price-block.json",
  "title": "Price Block",
  "x-adcp-hoist": true,
  "type": "object",
  "properties": {
    "cpm": { "type": "number" },
    "currency": { "type": "string" }
  }
}

Why opt-in for complex objects

Pure enums hoist automatically (see hoistDuplicateInlineEnums) because merging two structurally-identical enums is semantics-preserving. Complex objects are different — structural identity ≠ semantic identity. BriefAsset (proposed creative spec) and VASTAsset (delivered video creative) currently share fields but represent different lifecycle concepts; auto-merging them would create cross-tool coupling the source schemas don’t express, and would be hard to unwind once SDKs codegen against the merged type. x-adcp-hoist makes the share-or-split decision deliberate per schema.

Bundler behavior

  • Hoists at any occurrence count (≥1). The directive declares intent — “this is a canonical named type” — so adding a second reference later never changes the codegen surface.
  • title is required. Missing or empty title → build-time error. The directive is meant to be deliberate.
  • Same title + different shape is a build-time error. Two marked schemas authored with the same title but distinct fields would otherwise silently suffix one to Foo2, defeating the directive’s “canonical name” guarantee.
  • Collision with a pre-existing $defs key is suffixed (PriceBlock2), matching the convention used by the pure-enum hoist.
  • Stripped from bundled output — both from the canonical $defs entry and from any stray marker that was authored inside a pre-existing $defs block.

SDK / codegen impact

Adding x-adcp-hoist to a previously-inlined source schema is wire-compatible (the bundled schema still validates the same payloads) but is a codegen-shape change: TypeScript / Python / Go type generators that previously emitted an anonymous inline type (often Foo1, Foo2, …) will now emit a single named type. SDK adopters maintain rename aliases per their own deprecation policy — see adcp-client#942 for the client-side rename/alias tracking.

Conformance

  • Validators MUST ignore x-adcp-hoist per draft-07 §6 (unknown keywords are tolerated). The directive has no wire semantics.
  • Source-tree consumers (third parties that dereference static/schemas/source/... directly rather than the bundled artifacts) MUST treat x-adcp-hoist: true as a no-op annotation. The schema’s content is the contract.
  • Bundlers other than scripts/build-schemas.cjs MAY honor the directive or ignore it; a bundler that ignores it produces a wire-compatible bundle with un-deduped inline copies.

History

  • Introduced in #4557. Successor to #3145 phase 2.

Future extensions

New x-adcp-* keywords are added in minor releases. Consumers MUST tolerate unknown x- keywords without erroring. The convention reserves the x-adcp- namespace; vendor-specific or deployment-specific annotations SHOULD use a vendor-specific prefix (e.g., x-yourorg-) to avoid collision.