Skip to content

Releases: adcontextprotocol/adcp

v3.0.8

08 May 14:26
13f8f4b

Choose a tag to compare

Patch Changes

  • 8f82d46: fix(compliance): UUID-aliased idempotency_keys across remaining storyboard scenarios

    Extends the #4218 precedent (measurement_terms_rejected) to the rest of the suite. 15 storyboard steps across 9 scenarios still shipped hardcoded idempotency_key literals on state-mutating tasks (create_media_buy, sync_creatives, sync_plans, update_media_buy). The runner shifts dynamic start_time substitutions forward to keep buys future-dated, so against a long-running seller deployment those static keys collide cross-run with the same key + a different canonical body, arming the spec-mandated IDEMPOTENCY_CONFLICT (or, when the seller's emit shape changed between runs, replaying a now-spec-non-compliant cached payload — the production failure mode that surfaced this).

    Switch every remaining literal to $generate:uuid_v4#<scenario>_<step> so each storyboard run mints fresh keys and never collides with stale cached state. Affected scenarios: creative_fate_after_cancellation (5), governance_approved, governance_conditions, governance_denied, governance_denied_recovery (3), invalid_transitions, inventory_list_no_match, inventory_list_targeting, pending_creatives_to_start.

    Closes #4230.

v3.0.7

08 May 11:50
7d656da

Choose a tag to compare

Patch Changes

  • 866abe2: docs(creative): tighten type column in the list_creatives filtering options table to match core/creative-filters.json. accounts now shows AccountRef[] (was array), format_ids shows FormatID[] (was format_id[], matching the casing used in list_creative_formats, get_products, and create_media_buy), and statuses links to CreativeStatus rather than the under-specified string[]. Docs only — no schema or wire-format change. Patch-eligible per the non-normative-docs rule in .agents/playbook.md.

  • b2f7a3d: fix(compliance): measurement_terms_rejected — UUID-aliased idempotency_keys + spec-aligned narrative

    The media_buy_seller/measurement_terms_rejected storyboard shipped hardcoded idempotency_key literals on both create_media_buy steps. Combined with runner-side dynamic start_time substitution (the runner shifts stale dates forward to keep the buy future-dated), this produced same key + different body on every run against a long-running seller deployment, arming the spec-mandated IDEMPOTENCY_CONFLICT on the seller side. Switch to $generate:uuid_v4#… aliases so each run mints fresh keys (matches the established pattern across the storyboard suite).

    Also rewrites the narrative, which previously told implementers the buyer "retries the same create_media_buy idempotency_key with an adjusted payload" — a direct spec violation — to describe minting a fresh key for the retry.

    Closes #4219. Refs adcontextprotocol/adcp-client#1586.

v3.0.6

03 May 18:08
2cea1dc

Choose a tag to compare

Patch Changes

  • 91b6e2c: spec(errors): wire-placement guidance for GOVERNANCE_DENIED and GOVERNANCE_UNAVAILABLE

    error-code.json defined the codes' semantics but didn't say WHERE in the response they appear. Different storyboards interpreted differently — issue #3914 surfaced one mismatch where the brand-rights compliance storyboard expected expect_error: code: GOVERNANCE_DENIED even though acquire_rights already has a first-class AcquireRightsRejected discriminated arm with reason. Adopters returning the spec-correct Rejected shape were failing the storyboard.

    The enumDescriptions for both codes now state placement explicitly:

    • GOVERNANCE_DENIED — structured business outcome, not a system error. When the task response defines a structured rejection arm (e.g., AcquireRightsRejected), that arm is the canonical denial shape — populate status: "rejected" + reason, do NOT additionally emit the code in errors[] or adcp_error, and do NOT flip transport-level failure markers. When the task has no rejection arm (e.g., create_media_buy returns the Error arm), populate errors[].code AND adcp_error.code per the two-layer model and DO flip transport markers.
    • GOVERNANCE_UNAVAILABLE — system error, governance call failed at all. Always populate both layers with the code and flip transport markers. Sellers MUST NOT use a structured rejection arm for unavailability even when the task offers one — the buyer's recovery semantics differ (retry-with-backoff vs. restructure-or-escalate).

    The contrast resolves the question the storyboard mismatch surfaced: thrown adcp_error is reserved for governance-call failure modes (parallel to GOVERNANCE_UNAVAILABLE), not for adopter-controlled denials.

    The MUST NOT against dual-emission isn't a behavior change — AcquireRightsRejected and CreativeRejected already declare not: { required: [errors] } at the schema layer, so emitting errors[] alongside a rejection arm was already a schema violation. The doc-comment makes the rule discoverable from the error code without changing what conformant senders produce.

    Also adds a parallel storyboard-authoring note in error-handling.mdx: when the task response has a discriminated rejection arm, assertions should use check: field_value, path: "status", value: "rejected" rather than check: error_code. The existing error_code guidance is correct for tasks without a rejection arm; the new note covers the rejection-arm path that surfaced via #3914.

    Closes the doc-comment item on #3918; companion to #3914 (storyboard fix is separate work).

  • 91b6e2c: spec(conventions): reserve ctx_metadata as adapter-internal round-trip key

    Reserves the top-level key ctx_metadata on AdCP resource objects (Product, MediaBuy, Package, Creative, AudienceSegment, Signal, RightsGrant) as a publisher-to-SDK round-trip cache for adapter-internal state. SDKs MUST strip the key before wire egress and MUST emit a warning-level log entry when stripping, so operators can detect accidental collisions with existing adapter code. Buyers never see this field.

    The convention is non-binding at the wire level — these resources already declare additionalProperties: true so existing payloads remain valid. The reservation locks the keyword name before two SDKs converge on it accidentally and ship divergent semantics. PropertyList and CollectionList are out of scope (additionalProperties: false) until a follow-up PR widens those schemas.

    Closes #3640.

  • e4af188: docs(skill): document the four implementation-dependent issues[] fields callers may see

    skills/call-adcp-agent/SKILL.md already documents the three required issues[] fields (pointer, keyword, variants) that every conformant validator surfaces. Adds the four optional fields a calling agent will encounter when the seller's validator opts into them — discriminator, schemaId, allowedValues, hint — with a one-line preface clarifying these are implementation-dependent (not every validator emits them) and an updated recovery order: read hint first when present, then discriminator, then walk variants.

    Two new rows added to the symptom-fix lookup table for the same fields.

    No wire-format change. Pure documentation: shipping these fields is already a valid validator extension; this just gives callers a curated path through them.

    Surfaced from the @adcp/sdk side after PR #1283 / #1309 added the fields and PR #1268 / #1361 hit recurring drift between the local SDK skill copy (which already documented them) and the upstream bundle (which didn't). With this merged, the SDK's npm run sync-schemas no longer rewrites the file out from under contributors.

v3.0.5

02 May 23:25
1cb57a6

Choose a tag to compare

What's in 3.0.5

Three additive 3.0.x changes plus a CI plumbing fix. Wire format unchanged for any 3.0 agent that doesn't claim a new optional surface.

For adopters:

  • Adopting identity.brand_json_url from #3690 on 3.0? Bump to 3.0.5. 3.0.4 and earlier rejected the field at validation; 3.0.5's identity.additionalProperties: true accepts it. Mirrors what main shipped post-#3690.
  • Running brand-rights conformance? Spec-compliant agents that return rights_id (per acquire-rights-response.json) now pass rights_acquisition and stop cascade-skipping rights_enforcement. Storyboard YAML was reading the wrong field name. Closes #3892.
  • Authoring multi-agent storyboards? New optional top-level default_agent: <key> field lets you encode topology intent in YAML once instead of re-asserting it on every CI invocation. Closes #3894.
  • Maintaining the release pipeline? Forward-merge auto-resolution chain is now complete — every Version Packages cut auto-creates the forward-merge PR without manual intervention.

For full context, migration guidance, and the security model around the relaxed identity validator, see Release Notes § 3.0.5.

---### Patch Changes

  • a4bd513: spec(capabilities): relax identity.additionalProperties to true on get-adcp-capabilities-response

    Forward-compat fix for 3.0.x. The identity object was schema-closed (additionalProperties: false), so any operator that adopted a forward-compatible field — notably identity.brand_json_url from #3690, which was always intended to be readable by 3.0-pinned implementers without a schema bump — would have its capabilities response rejected by strict 3.0 validators (e.g., @adcp/sdk's createAdcpServer default).

    Mirrors the additionalProperties: true already shipped on main post-#3690. Strictly additive: the closed property list (per_principal_key_isolation, key_origins, compromise_notification) is unchanged; receivers that ignore unknown fields keep working; receivers that look for new identity fields gain forward-compat without waiting for a 3.x bump.

    The forward-compat narrative in security.mdx ("3.0-pinned implementers can adopt the field today without bumping") depends on this relaxation being live in shipped schemas — without it, the spec advice contradicts the schema.

  • d98c9e4: spec(storyboard-schema): add optional storyboard-level default_agent field

    Closes #3894. Adds an optional top-level default_agent: <key> field to the storyboard authoring schema (static/compliance/source/universal/storyboard-schema.yaml).

    default_agent is the logical name (sales, governance, creative, etc.) the multi-agent runner falls back to when a step has no step.agent override and the tool has no unique specialism claimant in the runtime agents map. Resolved against the agents option passed to runStoryboard({ agents: {…} }) — see adcp-client#1066 and adcp-client#1355.

    The runner already accepts default_agent via run-options. This change lets storyboard authors encode the topology intent in YAML once, rather than re-asserting --default-agent sales on every CI invocation. Cross-domain tools (sync_creatives, list_creative_formats, comply_test_controller) become deterministic without per-step agent: overrides.

    Strictly additive and backward-compatible:

    • Single-agent runs ignore the field (precedent: requires_scenarios, controller_seeding).
    • Existing 3.0.x storyboards keep working unchanged.
    • Pre-existing run-options default_agent keeps the lower-precedence fallback slot.

    Resolution order (runner contract):

    1. Step-level agent: override.
    2. Unique specialism claimant in the runtime agents map.
    3. Storyboard-level default_agent (this field).
    4. Run-options default_agent.
    5. Fail-fast (unrouted_step).

    Mirrors the provides_state_for precedent (#3775) for adding optional storyboard-schema fields on 3.0.x — small, additive authoring affordances that adopters need today and that don't bind 3.0 wire shape.

v3.0.4

02 May 11:35
4555f01

Choose a tag to compare

Patch Changes

  • 78b1dc4: spec(errors): tighten AUTH_REQUIRED prose to warn on retry storms (3.0.x prose-only backport of #3739)

    AUTH_REQUIRED conflates two operationally distinct cases — credentials missing (genuinely correctable) and credentials presented but rejected (terminal — needs human rotation). A buyer agent treating both as correctable will retry-loop on revoked tokens, hammering seller SSO endpoints in a pattern indistinguishable from a brute-force probe.

    The 3.1 line splits this into AUTH_MISSING and AUTH_INVALID (#3739). 3.0.x cannot adopt the split — adding new enum values violates the maintenance line's semver rules. This change is the prose-only backport: the wire code stays AUTH_REQUIRED with recovery: correctable, but the description and enumMetadata.suggestion now spell out the two sub-cases and the SHOULD-NOT-auto-retry rule for the rejected-credential case. SDKs running against 3.0.x sellers can apply the operational distinction at the application layer.

    Updates:

    • static/schemas/source/enums/error-code.jsonenumDescriptions.AUTH_REQUIRED and enumMetadata.AUTH_REQUIRED.suggestion rewritten to call out both sub-cases and the retry-storm risk; cross-references the 3.1 split.
    • docs/building/implementation/error-handling.mdx — adds an AUTH_REQUIRED sub-cases callout under the Authentication and Access table; updates the example switch to branch on whether credentials were attached.

    Wire format unchanged. No new enum values. No recovery classification change at the structured level. Senders that already emit AUTH_REQUIRED keep working; receivers gain the documented sub-case discipline.

    Closes the 3.0.x portion of #3730. The full split lands in 3.1.0 via #3739.

  • 78b1dc4: spec(error): standardize VALIDATION_ERROR issues[] as a normative field on core/error.json

    Closes #3059. Adds an optional top-level issues array to the standard error envelope, normalizing what @adcp/client (and prospectively adcp-go / adcp-client-python / hand-rolled sellers) already need for multi-field validation rejections.

    Why minor: new optional field on a published schema (core/error.json). Existing senders/receivers stay conformant — the field is additive. Receivers that ignore unknown fields keep working; receivers that look for it gain a richer pointer map without parsing message text.

    Shape: each entry is { pointer (RFC 6901), message, keyword, schemaPath? }. schemaPath MAY be omitted in production to avoid fingerprinting oneOf branch selection on adversarial payloads.

    Backward compatibility with field (singular): when both are present, sellers SHOULD set field to issues[0].pointer. Pre-3.1 consumers reading only field get the first failure; 3.1+ consumers prefer the top-level issues.

    details.issues mirror: sellers MAY mirror issues[] into details.issues for backward compat with consumers reading from details. New consumers should prefer top-level.

    Updates:

    • static/schemas/source/core/error.json — adds issues property with item shape
    • docs/building/implementation/error-handling.mdx — adds issues to the error-envelope field table; clarifies field/issues interaction
  • 78b1dc4: spec(manifest): publish manifest.json + structured enumMetadata to stop SDK drift (adcp#3725) — 3.0.x backport

    Hand-cherry-picked from #3738 onto 3.0.x. The original enumMetadata block on main references three error codes (SCOPE_INSUFFICIENT, READ_ONLY_SCOPE, FIELD_NOT_PERMITTED) that don't exist in 3.0.x's enum; this version trims those entries so the structured metadata covers exactly the 45 codes 3.0.x ships. The build-time lint enforces that coverage invariant — there is no way to silently drift enumMetadata away from the published enum.

    Patch-bump rationale: pure additive metadata block on a published schema, plus a new buildable artifact. No new wire fields, no enum value additions, no breaking changes for any conformant 3.0 agent.

    Adds two additive artifacts to every released schema bundle:

    1. enums/error-code.json gains an enumMetadata block. Every error code now carries structured recovery (correctable | transient | terminal) and suggestion fields. SDKs MUST consume this block instead of parsing Recovery: X prose out of enumDescriptions. A build-time lint rejects any drift between the structured value and the prose. Root cause for adcp-client#1135 (17 missing codes, 3 wrong recovery classifications shipped in TS SDK for over a year).
    2. manifest.json at /schemas/{version}/manifest.json (and /schemas/latest/manifest.json for nightly codegen). Single canonical artifact listing every tool (with protocol, mutating, request_schema, response_schema, async_response_schemas, specialisms), every error code (with recovery, description, suggestion), an error_code_policy block (defining default_unknown_recovery so SDKs handle non-spec codes from non-conforming sellers correctly), and every storyboard specialism (with protocol, entry_point_tools, exercised_tools). Validates against /schemas/{version}/manifest.schema.json. Generated deterministically from existing source — no new authored content. Lets SDKs derive their internal tool/error tables from one place at codegen time instead of hand-transcribing the spec.

    mutating is derived using the same classifier the idempotency-key lint enforces (single source of truth — manifest and lint can never disagree). The read-only verb pattern was tightened in the process: it now anchors at the start so tools like create-collection-list and delete-property-list are no longer mis-classified as read-only because they happen to contain -list- mid-name. search- was added as a read-only verb.

    Specialisms expose two distinct tool sets per #3725 review feedback: entry_point_tools (the curated minimal contract from index.yaml.required_tools — what the spec asserts implementers MUST ship) and exercised_tools (the full surface — union of own phases and every linked scenario, derived by walking phases[].steps[].task and resolving requires_scenarios). SDK authors should size their tool registration against exercised_tools to ensure they handle every call the conformance kit will make.

    Migration: SDKs targeting 3.0.x continue to work unchanged — enumDescriptions and the existing index.json are retained verbatim. SDKs targeting 3.1+ should switch to enumMetadata for error recovery and manifest.json for tool/specialism enumeration. The prose "Recovery: X" sentence embedded in each enumDescriptions value is stripped from the manifest's per-code description to avoid double-encoding; it remains in enumDescriptions for the human-readable narrative until a future minor formally deprecates it. Until then, the lint guarantees both surfaces stay synchronized.

  • 78b1dc4: spec(url-asset): add SHOULD on url_type, role-based fallback, and mechanism-vs-purpose clarification (#2986 step 2)

    url_type was optional with no fallback rule, so a conformant URL asset that omitted it left receivers guessing — buyers would either pick a default mechanism (with bad blast-radius if a clickthrough fired as a pixel) or refuse to render. Two parallel vocabularies (url-asset-type mechanism: 3 values; url-asset-requirements.role purpose: 6 values) compounded the confusion because the docs treated them as the same thing.

    This change:

    • Adds a top-level description on url-asset stating senders SHOULD include url_type on every URL asset, and defining the receiver fallback: when url_type is absent, receivers SHOULD fall back to the format's url-asset-requirements.role (clickthrough/landing_page → clickthrough mechanism; *_tracker roles → tracker_pixel); when neither is present, receivers MAY reject rather than guess.
    • Updates the url_type property description to frame it explicitly as the receiver's invocation mechanism, and points at the role fallback for senders that omit it.
    • Updates url-asset-requirements.role description to call out the mechanism-vs-purpose distinction (a click_tracker slot validly accepts a tracker_pixel URL).
    • Rewrites docs/creative/asset-types.mdx URL Asset section, replacing the old "you only need to supply the url value" guidance and the incorrect enum list (impression_tracker/video_tracker/landing_page — those were the requirement-side role values, not url_type values) with the actual clickthrough/tracker_pixel/tracker_script enum, the SHOULD note, and the role fallback table.

    Wire format unchanged. Existing senders that already include url_type are unaffected. Senders that omit url_type continue to validate but now have explicit receiver semantics; in 4.0 we plan to make url_type required (separate change). Closes step 2 of the rollout proposed on adcp#2986.

v3.0.3

01 May 20:06
8dc3d15

Choose a tag to compare

Patch Changes

  • a83a2aa: docs(creative-channels): replace invalid "url_type": "tracker" with "url_type": "tracker_pixel" in display, audio, carousels, and DOOH channel docs to match the url-asset-type.json enum (clickthrough / tracker_pixel / tracker_script). Addresses adcp#2986 step 1 (3.0.x docs cleanup). Wire format unchanged — the published schema enum already excluded "tracker", so the channel docs were emitting an invalid value sellers could not validate against.

  • dabd223: Add optional provides_state_for: <step_id> | <step_id>[] field to the storyboard step schema, declaring that a stateful step's pass establishes equivalent state for the named peer step(s) in the same phase. Pairs with the cascade-skip mechanism in @adcp/sdk 6.5.0+: when a peer step would otherwise grade missing_tool or missing_test_controller, the substitute waives the cascade and the runner grades the peer with skip reason peer_substituted (new in runner-output-contract.yaml).

    Storyboard schema (static/compliance/source/universal/storyboard-schema.yaml): documents the field next to contributes_to, including the all-of array semantics, same-phase-only constraint, target-stateful / substitute-stateful requirement, and acyclic-peer-graph rule.

    Runner output contract (static/compliance/source/universal/runner-output-contract.yaml): adds the peer_substituted skip reason to skip_result.reasons with detail format "<this_step_id> state provided by <peer_phase_id>.<peer_step_id>". Kept distinct from peer_branch_taken (branch-set routing) and not_applicable (coverage gap).

    Specialism YAML (static/compliance/source/specialisms/sales-social/index.yaml): declares provides_state_for: sync_accounts on the list_accounts step in account_setup. Lets explicit-mode social platforms (Snap, Meta, TikTok) — which intentionally pre-provision advertiser accounts out-of-band and expose only list_accounts — graduate from 1/9/0 to 9/10 on the sales_social storyboard once the SDK cache refreshes against this version.

    Build-time validation (scripts/lint-storyboard-provides-state-for.cjs, tests/lint-storyboard-provides-state-for.test.cjs): new lint rule wired into build-compliance.cjs covering shape, self-reference, unknown target, cross-phase reference, target-stateful, substitute-stateful, and direct-cycle violations. Source tree passes with the one new declaration above.

    Pure additive change; existing storyboards without the field keep their current cascade behavior. Backports to the 3.0.x line per #3734.

    Closes #3734.

v3.0.2

30 Apr 02:29
22a69cf

Choose a tag to compare

Patch Changes

  • 9dcf7aa: Add envelope_field_present check type to the storyboard schema and update v3-envelope-integrity.yaml to use it for the status presence assertion. The new check type walks protocol-envelope.json rather than the step's response_schema_ref, eliminating the static-analysis VERIFIER_UNREACHABLE gap in adcp-client's storyboard-drift verifier. Requires adcp-client#1045.
  • 9dcf7aa: Promote the shared asset-variant oneOf union to a canonical core/assets/asset-union.json schema. Both creative-asset.json and creative-manifest.json now reference this single file instead of inlining identical oneOf arrays. This eliminates the VASTAsset1, DAASTAsset1, BriefAsset1, and CatalogAsset1 codegen artifacts emitted by json-schema-to-typescript when the same union is encountered through multiple parent schemas. Wire format and validation semantics are unchanged.

v3.0.1

28 Apr 12:44
2a24ca5

Choose a tag to compare

3.0.1 is a stable-surface no-op for 3.0-conformant agents. No changes required.

📖 Curated release notes: https://adcontextprotocol.org/docs/reference/release-notes#version-301

TL;DR

  • Stable wire surface unchanged. No new fields, no renamed fields, no new enum values, no deprecations on stable schemas.
  • Skills now bundle in /protocol/3.0.1.tgz — the original driver. Re-cutting at 3.0.0 would have invalidated cosign attestations bound to the original 3.0.0 SHA-256.
  • Spec polish (no wire change): acquire_rights validation MUSTs (#2680, #2681), get_signals pagination precedence, URL canonicalization on brand.json agent URLs, v3 envelope integrity schema constraint.
  • Experimental surfaces (governance mode, TMP seller_agent) gain small additive fields per the experimental-status contract.
  • Conformance harness gains force_task_completion and seed_creative_format scenarios — sandbox-only.
  • One docs-level deprecation: get_signals top-level max_results (still works in 3.x; removed in 4.0).

Adopter action

Audience Action
3.0-conformant production agent Nothing.
SDK consumer Bump ADCP_VERSION from 3.0.0 to 3.0.1.
Governance / TMP implementer Review the additive fields above.
get_signals caller using top-level max_results Migrate to pagination.max_results.

Detailed change list

See CHANGELOG.md § 3.0.1 for the per-PR detail (18 patch changes).

Verification

  • Protocol tarball: https://adcontextprotocol.org/protocol/3.0.1.tgz (2.15 MB, cosign-signed)
  • Schemas: https://adcontextprotocol.org/schemas/3.0.1/
  • Compliance: https://adcontextprotocol.org/compliance/3.0.1/
  • Docs snapshot: https://adcontextprotocol.org/docs/3.0/ now serves the 3.0.1 frozen content.

AdCP v3.0.0

22 Apr 09:53
4472eb2

Choose a tag to compare

AdCP 3.0 is the first stable release of the Ad Context Protocol. The headline change is a trust-surface overhaul: mandatory idempotency keys, RFC 9421 request signing, signed governance contexts, compliance-gated test vectors, and GDPR/EU AI Act invariants baked into the schema.

See Migration from rc.3, What's new in v3, or the full release notes.

Protocol tarball3.0.0.tgz below is signed with Sigstore cosign (keyless, bound to the Release workflow on main). To verify:

cosign verify-blob 3.0.0.tgz \
  --certificate 3.0.0.tgz.crt \
  --signature 3.0.0.tgz.sig \
  --certificate-identity-regexp 'https://github.com/adcontextprotocol/adcp/' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com'

Expected SHA-256: 04481e277089bebe551d3dc1294faab56aa876a7c08e0f010a8ca6ba41a06af4


See release notes for migration guidance, or prerelease upgrade notes for rc.3 adopters.

Breaking Changes — trust surface

  • 43586d6, c1d2ff1: Require idempotency_key on all mutating requests; formalize seller declaration as discriminated oneOf (#2315, #2436, #2447). Every mutating task now requires an idempotency_key in the request envelope, matching ^[A-Za-z0-9_.:-]{16,255}$; AdCP Verified additionally requires a cryptographically-random UUID v4. Fresh key per logical operation; reuse only to retry a failed request with the identical payload.

    Sellers declare dedup semantics on get_adcp_capabilities as adcp.idempotency = { supported: true, replay_ttl_seconds: <1h–7d, 24h recommended> } OR { supported: false }. When supported: true, sellers respond replayed: true on exact replay, IDEMPOTENCY_CONFLICT when the same key accompanies a different payload, and IDEMPOTENCY_EXPIRED after the declared TTL. When supported: false, sending an idempotency_key is a no-op — the seller will NOT return conflict/expired errors, and a naive retry WILL double-process. Buyers must use natural-key checks (e.g., get_media_buys by buyer_ref) before retrying spend-committing operations against non-supporting sellers. Clients MUST NOT assume a default — a seller without this block is non-compliant.

    Since supported: true is a trust-bearing claim, buyers and conformance runners SHOULD probe by replaying with a deliberately-mutated payload — a conformant seller MUST return IDEMPOTENCY_CONFLICT. Sellers declaring supported: true MUST pass this probe in the baseline compliance storyboard before the declaration is considered verified.

  • aaace06: Model IO approval at the task layer, not as a media-buy status (#2270, #2351). MediaBuy.pending_approval is removed. Approvals are now modeled as explicit approval tasks with their own lifecycle, state, and audit trail — decoupled from the media-buy state machine. Enables sales-guaranteed sellers to implement human-in-the-loop approval without overloading media-buy status semantics.

  • e6dd73a: GDPR Art 22 / EU AI Act Annex III enforced as JSON Schema invariants (#2310, #2338). budget.authority_level enum is removed and replaced by two orthogonal fields: budget.reallocation_threshold (number ≥ 0, or reallocation_unlimited: true) for budget autonomy, and plan.human_review_required (boolean) for per-decision review under Art 22. Cross-field if/then rejects human_review_required: false when policy_categories contains fair_housing, fair_lending, fair_employment, or pharmaceutical_advertising, or when any resolved policy carries requires_human_review: true. revisionHistory is append-only; downgrading human_review_required requires a human_override artifact (≥20-char reason, email approver, 24h-fresh approved_at). eu_ai_act_annex_iii seeded as a registry regulation. data_subject_contestation on brand.json (and inline on brand-ref.json) satisfies Art 22(3) discovery.

  • ec06d47, 31aab3a: Specialism taxonomy finalized (#2332, #2336). inventory-lists specialism renamed to property-lists. New collection-lists specialism split out as a sibling under governance. Account migration on specialism declarations complete — agents declare specialism ownership via the account surface. audience-sync already reclassified from governance to media-buy in #2300.

  • 84b322c: Rename compliance taxonomy domainsprotocols (#2300). /compliance/{version}/domains/ becomes /compliance/{version}/protocols/. supported_protocols value maps to compliance path via snake_case → kebab-case (e.g. media_buyprotocols/media-buy/). audience-sync reclassified from governance to media-buy to match its tool family. Compliance runner path resolution, index.json structure, and catalog documentation all reflect the rename.

Breaking Changes

  • 80ecf76: Simplify capabilities model for 3.0 (#2143). Remove redundant boolean gates — object presence is the signal. Make table-stakes fields required.

    Removed fields:

    • media_buy.reporting (product-level reporting_capabilities is source of truth)
    • features.content_standards / features.audience_targeting / features.conversion_tracking (object presence replaces booleans)
    • content_standards_detail → renamed to content_standards
    • brand.identity (implied by brand protocol)
    • trusted_match.supported (object presence)
    • targeting.device_platform / targeting.device_type (implied by media_buy)
    • targeting.audience_include / targeting.audience_exclude (implied by audience_targeting)

    Required fields:

    • reporting_capabilities on every product (see product.json)
  • a90700f: Revert geo capability flattening (#2157). Restore geo_countries and geo_regions (booleans) and geo_metros and geo_postal_areas (typed objects with additionalProperties: false) as primary capability fields. Remove flat array alternatives (supported_geo_levels, supported_metro_systems, supported_postal_systems) introduced in #2143.

  • 95f1174: Media buy status lifecycle (#2034). Rename pending_activationpending_start. Add pending_creatives status for approved buys with no creatives assigned. Add top-level compliance_testing: { scenarios: [...] } capability block (not a supported_protocols value) for declaring comply_test_controller support.

  • 100b740: Move storyboards into the protocol as /compliance/{version}/ (#2176). Add specialisms field to get_adcp_capabilities with 21 specialisms across 6 domains (media-buy, creative, signals, governance, brand, sponsored_intelligence). Promote sponsored_intelligence from specialism to full protocol in supported_protocols. Rename broadcast-platformsales-broadcast-tv, social-platformsales-social. Merge property-governance + collection-governance into inventory-lists. Add status: preview marker for 3.1 archetypes (sales-streaming-tv, sales-exchange, sales-retail-media, measurement-verification). Publish per-version protocol tarball at /protocol/{version}.tgz for bulk sync. New enums/specialism.json and enums/adcp-domain.json.

  • 07d82dd: Require account on update_media_buy for governance and account resolution parity with create_media_buy (#2179). Flatten preview_creative union schema into single object with request_type discriminant.

  • b674082: Add GOVERNANCE_DENIED to standard error codes with correctable recovery (#2194). Make signal_id required on get-signals-response signal items. Add context and ext fields to all request/response schemas (governance, collection, property, sponsored-intelligence, content-standards).

  • 60f2a9e: Generalize governance to all purchase types (#2014). Remove media_buy_id from governance schemas — governance_context is the sole lifecycle correlator. Add purchase_type field on check_governance and report_plan_outcome. Add budget allocations on plans for per-type budget partitioning. Audit logs group by governance_context instead of media_buy_id.

Minor Changes — trust surface

  • 9e1b0eb: RFC 9421 request signing profile (optional in 3.0, mandatory under AdCP Verified) (#2323). Agents MAY sign mutating requests using RFC 9421 HTTP Message Signatures with Ed25519 over a canonicalized covered-component list (including method, target URI, content-digest, and protocol-level fields). Published test vectors (request-signing/positive/*, request-signing/negative/*) and a 15-step verification checklist (alg allowlist, keyid cap-before-crypto, JWKS resolution via SSRF-validated fetch, replay dedup via jti). sf-binary encoding pinned (#2341) and URL canonicalization tightened (#2343) so independent implementations produce bit-identical canonical inputs. Verifier guidance at docs/building/implementation/security.mdx; test vectors at static/compliance/source/test-vectors/request-signing/.

  • 2e3ec71: Signed JWS governance_context (#2316). governance_context is a signed JWS produced by the governance agent and echoed by the buyer in the media-buy envelope. Sellers verify the signature using the governance agent's JWKS (resolved via sync_governance) and bind decisions to a specific buyer, plan, phase, and time. Replaces the opaque-string carrier from earlier 3.0 drafts. Enables sellers to reject stale or forged governance decisions without round-tripping to the governance agent. Fields: alg, typ, iss, sub, aud, phase, exp, iat, jti, plus governance-specific claims.

  • f2918f4: Signed-requests runner harness contract (#2350, #2353). Compliance runner declares a signed_requests harness profile: given a seller endpoint and a signing keypair, the runner...

Read more

AdCP v3.0.0-rc.2

15 Mar 23:38
3e793c0

Choose a tag to compare

AdCP v3.0.0-rc.2 Pre-release
Pre-release

AdCP 3.0.0-rc.2

Second release candidate for AdCP v3.

Highlights

  • Brand Protocol Rights Lifecycle: get_rights, acquire_rights, and update_rights for brand licensing
  • Structured visual_guidelines on brand.json for generative creative systems
  • Shows and episodes as first-class content dimensions on products
  • ai_media channel for AI platform advertising
  • Property governance integration via optional property_list filtering
  • Campaign governance and policy registry: sync_plans, check_governance, report_plan_outcome, and get_plan_audit_logs for plan-level governance and shared policies
  • Simplified account model with require_operator_auth determining auth/account behavior

Breaking changes since rc.1

See the full release notes and v3 overview for migration details.

Schemas

Available in dist/schemas/3.0.0-rc.2/.

Full changelog: https://github.com/adcontextprotocol/adcp/blob/main/CHANGELOG.md
Release notes: https://docs.adcontextprotocol.org/docs/reference/release-notes#version-300-rc2
What's new in v3: https://docs.adcontextprotocol.org/docs/reference/whats-new-in-v3