Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-canvases-coordinate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@adcp/sdk': patch
---

Adopt AdCP 3.2.0-beta.6 schemas, including coordinated placements, seller-rendered stateful display, creative component assets, and A2A 1.0 request-signing method names.
2 changes: 1 addition & 1 deletion ADCP_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.0-beta.5
3.2.0-beta.6
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ if (!artifact.name) { ... }

Used for receiving task completion/progress notifications. Placement differs by protocol:

- **AdCP 3.2.0-beta.5 on A2A**: Goes in skill parameters as
- **AdCP 3.2.0-beta.6 on A2A**: Goes in skill parameters as
`push_notification_config` (snake_case), including `operation_id`. The native
A2A `params.configuration.pushNotificationConfig` is a distinct transport
facility; the SDK may retain it for compatibility, but it does not replace
Expand Down
3 changes: 2 additions & 1 deletion docs/TYPE-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AdCP Type Summary

> Generated at: 2026-08-23
> Generated at: 2026-08-24
> @adcp/sdk v14.0.0-beta.7

Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
Expand Down Expand Up @@ -900,6 +900,7 @@ _Request:_
start_date: string
end_date: string
include_package_daily_breakdown: boolean
requested_metrics: object[]
time_granularity: Reporting Frequency
include_window_breakdown: boolean
attribution_window: object
Expand Down
4 changes: 2 additions & 2 deletions docs/development/WIRE-VERSION-COMPAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ How `@adcp/sdk` keeps a buyer pinned to one AdCP major version while talking to
## The shape of the problem

The SDK speaks one primary AdCP version on its public surface — `ADCP_VERSION`
in `src/lib/version.ts`. The SDK 14 beta pin is `3.2.0-beta.5`; maintained side
in `src/lib/version.ts`. The SDK 14 beta pin is `3.2.0-beta.6`; maintained side
bundles cover `3.1.18`, `3.0.25`, and v2.5. Every buyer-facing type, helper,
and example assumes the primary pin.

Expand All @@ -27,7 +27,7 @@ There is exactly one active legacy compat layer at a time today: `legacy/v2-5/`.

```
schemas/cache/
├── 3.2.0-beta.5/ # current SDK pin
├── 3.2.0-beta.6/ # current SDK pin
├── 3.1.18/ # maintained stable side bundle
├── 3.0.25/ # maintained stable side bundle
├── latest/ # symlink to the primary pin
Expand Down
14 changes: 8 additions & 6 deletions docs/guides/MEDIA-BUY-3.2-COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ routes it can still **call**. A 3.2 seller should make the compact lifecycle the
obvious path for new buyers without breaking a 3.0 or 3.1 buyer that already
calls the established names.

The SDK is pinned to the signed `3.2.0-beta.5` bundle. That exact prerelease
supersedes beta.4 and adds the normative async identity, cross-channel
convergence, webhook retry-horizon, and continuation-generation contract.
Beta.4 introduced flexible-window availability and the products-only legacy
purchase-continuation contract.
The SDK is pinned to the signed `3.2.0-beta.6` bundle. That exact prerelease
supersedes beta.5 and adds coordinated placements, seller-rendered stateful
display, creative component assets, and A2A 1.0 request-signing method names.
Beta.5 added the normative async identity, cross-channel convergence, webhook
retry-horizon, and continuation-generation contract; beta.4 introduced
flexible-window availability and the products-only legacy purchase-continuation
contract.

## MCP surface comparison

Expand Down Expand Up @@ -74,7 +76,7 @@ const platform = {
createAdcpServerFromPlatform(platform, {
name: 'seller',
version: '1.0.0',
adcpVersion: '3.2.0-beta.5',
adcpVersion: '3.2.0-beta.6',
});
```

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/PUSH-NOTIFICATION-CONFIG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Push Notification Config

Push notification config tells the AdCP agent where to send async task status updates via webhook. In AdCP 3.2.0-beta.5 it is application-layer request data on MCP, A2A, and REST. The client injects it automatically when `webhookUrlTemplate` is configured.
Push notification config tells the AdCP agent where to send async task status updates via webhook. In AdCP 3.2.0-beta.6 it is application-layer request data on MCP, A2A, and REST. The client injects it automatically when `webhookUrlTemplate` is configured.

## How It Works

Expand Down
11 changes: 9 additions & 2 deletions docs/llms.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ad Context Protocol (AdCP)

> Generated at: 2026-08-23
> Generated at: 2026-08-24
> Library: @adcp/sdk v14.0.0-beta.7
> AdCP major version: 3
> Canonical URL: https://adcontextprotocol.github.io/adcp-client/llms.txt
Expand Down Expand Up @@ -520,7 +520,7 @@ Request parameters for retrieving media buy status, creative approvals, and deli
Request parameters for retrieving comprehensive delivery metrics.

**Request:**
- Optional: `account: Account Ref`, `media_buy_ids: string[]`, `status_filter: Media Buy Status | object[]`, `start_date: string`, `end_date: string`, `include_package_daily_breakdown: boolean`, `time_granularity: Reporting Frequency`, `include_window_breakdown: boolean`, +3 more
- Optional: `account: Account Ref`, `media_buy_ids: string[]`, `status_filter: Media Buy Status | object[]`, `start_date: string`, `end_date: string`, `include_package_daily_breakdown: boolean`, `requested_metrics: object[]`, `time_granularity: Reporting Frequency`, +4 more

**Response (success branch):**
- Required: `reporting_period: object`, `currency: string`, `media_buy_deliveries: object[]`
Expand Down Expand Up @@ -1162,6 +1162,12 @@ Flow: `build_creative → sync_accounts → sync_governance → list_transformer
**Canonical format validate_input** — Validates 3.1 canonical-format dry-run semantics: structural pass/fail across canonical slots and unvalidatable_nondeterministic for seeded products.
Flow: `validate_input`

**CTV experience profile validate_input** — Validates AdCP 3.2 ctv_ad_experience matrix pairings, duration/interactivity constraint profiles, the menu focus/video pairing, and non-blocking activation-copy warnings via validate_input against seeded CTV products.
Flow: `validate_input`

**Premium display canonical validation** — Validates AdCP 3.2 seller_rendered_stateful_display supply-mode contracts (components, rendered_canvases, layered_source), single-state reveal shape, policy floors, and coordinated_placements sequence/serving_policy, alongside transition/canvas coverage and shared-slot resolution.
Flow: `validate_input`

### Campaign Governance

**Governance denial and human escalation** — Buyer's governance agent denies a media buy that exceeds spending authority, escalates to a human who approves with conditions.
Expand Down Expand Up @@ -1688,6 +1694,7 @@ Agents use the `recovery` classification to decide what to do: `transient` → r
| `FORMAT_NOT_SUPPORTED` | correctable | A requested creative operation route is not supported by this creative agent. On the canonical 3.2 path, returned when build_creative.target_capability_id(s), preview_creative.target_capability_id, or validate_input targets[] kind capability does not match an advertised creative.supported_formats[].capability_id carrying the requested operation. Also returned when preview renderer inference has zero or multiple compatible matches. Sellers SHOULD attribute the error to the selector field and MAY include supported capability IDs in error.details.supported_capability_ids when safe. Deprecated target_format_id(s) and preview format_id retain legacy named-format error attribution during the 3.x compatibility window. |
| `FORMAT_OPTION_UNRESOLVED` | correctable | Non-fatal advisory raised when a placement in `adagents.json` (or any consumer of `placement-definition.json`) carries `format_options[].format_option_id` referencing a `format_option_id` that does NOT exist in the file's top-level `formats[]`. The reference is broken — the publisher's catalog claims the placement accepts a format option that isn't declared. **Resolution scope is same-file only.** Cross-file `format_option_id` lookup is not supported by design (closes off format_option_id squatting across publisher boundaries — a malicious file cannot reference another publisher's format_option_id and claim its narrowing). Buyer SDKs MUST fail closed for the placement (drop the format from the placement's accepted format set) and MUST surface this code rather than silently dropping or guessing what the publisher meant. Surface placement: same single-mandate as the other FORMAT_* codes — SDKs that detect on consumption MUST augment the response's `errors[]` with `source: "sdk"`, `sdk_id`, `code: "FORMAT_OPTION_UNRESOLVED"`, `field` pointing at the offending placement (e.g., `placements[2].format_options[1].format_option_id`), and `error.details` SHOULD carry `{ placement_id, format_option_id, declared_format_options: [<list of format_option_ids actually in formats[]>] }` so the publisher can fix. |
| `FORMAT_PROJECTION_FAILED` | correctable | Non-fatal advisory raised when a legacy named format on a product cannot be projected to a canonical-formats `ProductFormatDeclaration` via the resolution order in `v1-canonical-mapping.json` (explicit `canonical` field → format_id_glob → structural match → fail-closed). The product is still valid on the legacy named-format path; only the 3.1+ `format_options` projection failed. Primarily a **consumer-SDK concern** — the seller didn't fail; the consumer-side SDK couldn't project on their behalf. `error.field` MUST point at the offending product (e.g., `products[3].format_ids[0]`); `error.details` SHOULD carry `{ format_id, product_id, resolution_failure: "no_explicit_canonical" | "no_registry_match" | "no_structural_match" }` so buyer SDKs can route remediation (suggest the seller add an explicit `canonical` field, or file a registry PR). **Surface placement (normative).** SDKs that detect this on consumption MUST augment the response's `errors[]` array with an entry carrying `source: "sdk"`, `sdk_id: "<package>@<version>"`, `code: "FORMAT_PROJECTION_FAILED"`, and the field+details described above. This is the single mandated surface — logger-only is insufficient and a separate lint-output channel is NOT acceptable (AdCP is a multi-hop agent network; warnings need to propagate across hops or each hop has to re-detect locally). Sellers MAY emit this code on their own response when they self-detect a non-projectable format on emit; producer-emitted entries omit `source` (or set `source: "producer"`). The response stays 200/success regardless of who emits; this is non-fatal. **Multi-hop deduplication.** Each hop that detects the same condition SHOULD deduplicate by `(code, field)` rather than re-emit. The existing entry's `sdk_id` identifies which earlier processor saw it first; downstream SDKs SHOULD NOT add a second entry for the same `(code, field)` pair unless they have materially different `error.details` (e.g., a different `resolution_failure` reason from a different registry version). See canonical-formats.mdx 'Dual emission and v2↔v1 projection' for the full rules. |
| `FORMAT_SHAPE_PROMOTED` | correctable | Non-fatal deprecation advisory raised when a 3.2-aware SDK encounters `format_kind: custom` with a `format_shape` that has been promoted to a first-class canonical. SDKs MUST preserve the declaration during its transition window and SHOULD augment the containing response's `errors[]` with `source: sdk`, `sdk_id`, this code, and `details: { format_shape, promoted_to, promotion_release, transition_end }`. Producers that self-detect their own legacy declaration MAY emit the same advisory with `source: producer`. Recovery is seller-side: dual-emit during the published transition window, migrate consumers, then replace the custom declaration with the promoted canonical. |
| `GOVERNANCE_DENIED` | correctable | A registered governance agent denied the transaction. Sellers MUST place the denial in the operation's structured rejection arm when one exists (e.g., `acquire_rights` → `AcquireRightsRejected`, or an `approval_webhook` delivery → `CreativeRejected`); otherwise in `errors[]` + `adcp_error`. Buyers MUST dispatch on the response's discriminated `status` first and fall back to `errors[].code` / `adcp_error.code` only when no rejection arm exists for that operation. The buyer may restructure the buy (e.g., reduce budget, split into smaller transactions), escalate to human spending authority, or contact the governance agent for details. Wire placement (full guidance). Governance denial is a structured business outcome, not a system error — the governance call SUCCEEDED and the agent returned a denial verdict. Two cases: 1. Operation or webhook payload defines a structured rejection arm. The arm IS the canonical denial shape. The seller populates `reason` (human-readable, propagating governance findings) and `suggestions` (optional) and does NOT additionally emit `GOVERNANCE_DENIED` in `errors[]` or `adcp_error`. The rejection arms enforce this at the schema layer: e.g., `AcquireRightsRejected` and `CreativeRejected` both declare `not: { required: [errors] }`, so dual-emission is already a schema violation. The code does not appear on the wire when the rejection arm is used. Transport-level success markers MUST NOT be flipped (HTTP 200, MCP `isError: false`, A2A `succeeded`) — the operation completed successfully and produced a structured response. 2. Operation response has no rejection arm (e.g., `create_media_buy` returns Success / Error / Submitted arms only). The seller populates `errors[].code: GOVERNANCE_DENIED` in the payload AND `adcp_error.code: GOVERNANCE_DENIED` on the envelope per the two-layer model in `error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model`. Transport-level failure markers DO flip in this case (HTTP 4xx, MCP `isError: true`, A2A `failed`) — the task could not produce a success artifact. The rule generalizes to any current or future operation or webhook payload whose response defines a discriminated rejection arm. In either placement, sellers SHOULD propagate governance findings verbatim — buyers' recovery decisions depend on what specifically was rejected. `GOVERNANCE_DENIED` is reserved for verdicts received from a reachable governance agent; if the governance call itself failed (timeout, network, config error), use `GOVERNANCE_UNAVAILABLE` instead. |
| `GOVERNANCE_UNAVAILABLE` | transient | A registered governance agent is unreachable. Sellers MUST place this code in `errors[]` + `adcp_error` (never a structured rejection arm) and flip transport-level failure markers (HTTP 5xx, MCP `isError: true`, A2A `failed`). Distinct from `GOVERNANCE_DENIED` (agent reachable and explicitly denied — see that code's wire-placement guidance). Wire placement (full guidance). Governance unavailability is a system error — the governance call FAILED (timeout, network, config error) and the seller could not get a verdict at all. Always populate both layers per the two-layer model in `error-handling.mdx#envelope-vs-payload-errors-the-two-layer-model`. Do NOT use a structured rejection arm for unavailability even when the task offers one — the buyer's recovery semantics differ (retry-with-backoff for unavailability vs. restructure-or-escalate for denial), and conflating them masks the system-error signal. |
| `IDEMPOTENCY_CONFLICT` | correctable | An earlier request with the same idempotency_key was processed with a different canonical payload within the seller's replay window. Distinct from CONFLICT (concurrent write) — this indicates the client reused a key across semantically different requests. |
Expand Down
8 changes: 5 additions & 3 deletions docs/migration-12-to-14.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Migrating from 12.x to 14 beta

This is the direct upgrade path for applications skipping SDK 13. SDK 14 includes both SDK 13's canonical-creative and security boundary changes and the AdCP `3.2.0-beta.5` preview surface. Treat it as two review checkpoints even if you deploy one package update.
This is the direct upgrade path for applications skipping SDK 13. SDK 14 includes both SDK 13's canonical-creative and security boundary changes and the AdCP `3.2.0-beta.6` preview surface. Treat it as two review checkpoints even if you deploy one package update.

AdCP prerelease pins are exact: beta.5 supersedes beta.4. Beta.2 added canonical
AdCP prerelease pins are exact: beta.6 supersedes beta.5. Beta.2 added canonical
compact proposal and direct-buy lifecycle storyboards through operational
control and MediaBuy readback; beta.4 adds flexible-window availability and
durable products-only legacy purchase continuations. Beta.5 defines stable
async identity, cross-channel terminal convergence, webhook retry horizons,
and crash-safe continuation generation replacement.
and crash-safe continuation generation replacement. Beta.6 adds coordinated
placements, seller-rendered stateful display, creative component assets, and
A2A 1.0 request-signing method names.

Install the beta explicitly:

Expand Down
Loading
Loading