Skip to main content
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.
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

Sub-keys

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: 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-open-payload

Classifies fields that look open-ended to SDK generators. The annotation is documentary and non-validating; the field’s JSON Schema still controls wire validation. Allowed authoring values: false is reserved for a future structured-but-extension-tolerant marker. Source schemas MUST NOT set x-adcp-open-payload: false until the repository defines at least one canonical use site and the generator contract for that value. For mixed fields, the annotation applies only to the object or decoded-JSON payload arm. Scalar arms still follow their declared schema. For example, an upstream recorded body may be a decoded JSON object when the content type is JSON-shaped and a string otherwise; x-adcp-open-payload: true marks the decoded JSON payload as intentionally open, not the string arm as an object model.
Use omission for legacy or not-yet-classified fields; do not use omission to mean “closed”.

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.

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.