Repository navigation
v9.0.0-beta.1
Pre-release
Pre-release
Install the SDK 9 beta
Published on PyPI as adcp==9.0.0b1.
The Python package version is 9.0.0b1; the release tag is v9.0.0-beta.1.
pip install 'adcp==9.0.0b1'This is a prerelease. Ordinary package resolution continues to select the stable SDK 8 series. Review the breaking changes and migration guidance below before upgrading.
Public ProductFormatDeclaration naming and generated validation remain a pre-GA follow-up (#1401). This beta preserves the existing cross-field and credential validation; a direct export rebind to the generated union would lose those protections.
9.0.0-beta.1 (2026-10-06)
⚠ BREAKING CHANGES
- types: public canonical creative models are real subclasses of the generated classes they refine, and canonical_creative.pyi is deleted, so mypy now enforces previously hidden required fields (ListCreativesResponse requires query_summary and pagination) and generated validators now apply (CreativeManifest requires format_id or format_kind)
- types: format_kind and format_kinds are open str on every generated and canonical model and no value is refused; compare with == instead of
is CanonicalFormatKind.xand check the vocabulary with adcp.types.is_canonical_format_kind - types: adcp_version and adcp_major_version are plain str and int on AcceptProposalRequest, BuyProductsRequest, ControlMediaBuyRequest, DeclineProposalsRequest, ListProductsRequest, RefineProposalsRequest, RequestProposalsRequest and SyncReportingStatusRequest (drop .root), and every task request and response gains AdcpRequest or AdcpResponse as its first base
- codegen: generated models are defined at adcp.types.domains.., and adcp.types.generated_poc.* is now a deprecated alias of the same module objects (DeprecationWarning, removed in v10); migrate with the prefix rename adcp.types.generated_poc. -> adcp.types.domains.
- codegen: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
- types: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
- codegen: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
- types: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
- codegen: 42 generated models reject documents they previously accepted. Each rejection is a document the model's own JSON Schema rejects. Code that constructs one of these models without any of its root required groups raises
ValidationErrorwhere it previously returned a model with every group fieldNone. - signing: Webhook verification no longer emits
webhook_signature_jwks_unavailable,webhook_signature_jwks_untrusted,webhook_signature_requiredorwebhook_signature_components_unexpected; JWKS discovery failures are nowwebhook_signature_key_unknown, and an unsigned webhook (or one carrying onlySignatureor onlySignature-Input) or a duplicated covered component is nowwebhook_signature_header_malformed.adcp.signing.errorsno longer definesWEBHOOK_SIGNATURE_JWKS_UNAVAILABLE,WEBHOOK_SIGNATURE_JWKS_UNTRUSTED,WEBHOOK_SIGNATURE_REQUIREDorWEBHOOK_SIGNATURE_COMPONENTS_UNEXPECTED: matchWEBHOOK_SIGNATURE_KEY_UNKNOWN/WEBHOOK_SIGNATURE_HEADER_MALFORMEDinstead, useWEBHOOK_ERROR_CODESfor the full list, and to keep retrying a receiver-side JWKS outage readSignatureVerificationError.transient(orWebhookOutcome.transient) rather than the code; the preciserequest_signature_*cause remains onexc.__cause__and in the WARNING log. - validation: generated models validate
boolean,integerandnumberfields strictly. A payload relying on pydantic's lax coercion —"yes"or1for a boolean,"1"ortruefor an integer,"1"for a number — now raisesValidationErrorinstead of being coerced, matching the bundled JSON Schema for the same tool. An integral float for an integer field (1.0) is still accepted and narrowed toint, because JSON Schema counts it as an integer. The bundled schema validator additionally enforcesformat: uriandformat: hostname, so a response carrying a malformed URL now fails response validation, which defaults to strict outside production. - codegen: resolving a pointer ref to its target removes the intermediate class the pointer previously generated, so
adcp.types._generated.__all__goes 3010 -> 2964: 49 names removed, 3 added. The removed names are artifacts of the defect, and the replacement is the shared type the field now points at. No deprecated aliases are provided. See the per-name replacement table above. - types: 114 generated classes stop being
RootModelsubclasses - 107 union roots and 7 single-model roots. A caller that reaches a wrapper's inner model through.root, or callsTypeName.model_validate(...)on a union root, changes at those sites: useTypeAdapter(TypeName).validate_python(payload), which honors the discriminator, and read the inner value directly instead of through.root. A single-model root keepsTypeName.model_validate(...). See the Breaking change section above for the migration. - signing:
adcp.signing.errorsno longer defines WEBHOOK_SIGNATURE_BRAND_JSON_URL_MISSING, WEBHOOK_SIGNATURE_CAPABILITIES_UNREACHABLE, WEBHOOK_SIGNATURE_BRAND_JSON_UNREACHABLE, WEBHOOK_SIGNATURE_BRAND_JSON_MALFORMED, WEBHOOK_SIGNATURE_BRAND_ORIGIN_MISMATCH, WEBHOOK_SIGNATURE_AGENT_NOT_IN_BRAND_JSON, WEBHOOK_SIGNATURE_BRAND_JSON_AMBIGUOUS, WEBHOOK_SIGNATURE_KEY_ORIGIN_MISMATCH or WEBHOOK_SIGNATURE_KEY_ORIGIN_MISSING, so importing any of them raises ImportError;adcp.signingnever re-exported them. No verifier emitted those strings and the webhook error taxonomy does not define them: replace each import withWEBHOOK_SIGNATURE_KEY_UNKNOWN("webhook_signature_key_unknown"), which is the code every webhook key-discovery failure already carried, and read the preciserequest_signature_*hop fromexc.__cause__or the WARNING log instead of the code.check_key_origin_consistency(..., code_family="webhook")now raiseswebhook_signature_key_unknownwhere it raisedwebhook_signature_key_origin_missingorwebhook_signature_key_origin_mismatch; matchwebhook_signature_key_unknown, or keep the defaultcode_family="request"for the distinctrequest_signature_key_origin_*codes. Codes emitted byverify_webhook_signature,verify_webhook_from_agent_urlandverify_request_signatureare unchanged. - types: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses.
issubclass(X, RootModel)is now False for those types, andX.model_dump/X.model_validate/X.model_json_schemano longer exist on them because they are no longer Pydantic models — useTypeAdapter(X)instead..rootreads andX(root=...)construction both still work behind a DeprecationWarning, so no existing call site has to change. See the BREAKING CHANGE section above for the migration steps. - signing:
allow_private=Truenow admits only RFC 1918, RFC 4193 unique-local and loopback destinations. The IANA special-use ranges it used to admit — link-local, multicast, the unspecified address, RFC 6598 carrier-grade NAT, documentation and benchmarking space, RFC 6890 protocol assignments, 240.0.0.0/4, 6to4, Teredo, NAT64, the IANA anycast and identifier ranges and unallocated IPv6 — are refused unless the caller also passes the newallow_special_use=True; cloud metadata addresses stay refused under both. Direct callers ofvalidate_resolved_ip,resolve_and_validate_host,validate_jwks_uri,build_ip_pinned_transport,build_async_ip_pinned_transportor the deprecatedabuild_ip_pinned_transportthat dial those ranges migrate by addingallow_special_use=Truenext toallow_private=True. The higher-levelallow_private_destinations=Truesurfaces — webhook delivery andWebhookSender, the audit sink, agent and brand.json resolution, and the built-in JWKS and revocation fetchers — forward onlyallow_privateand get no special-use relaxation: deployments that reached a special-use address through them must move the destination into RFC 1918, RFC 4193 or loopback space, or supply their own client or transport built withallow_special_use=Truewhere that surface accepts one. Loopback, RFC 1918 and RFC 4193 destinations, including theDockerLocalhostRewritetargets, are unaffected. - auth: Requests that supply different tokens in multiple accepted credential carriers now return HTTP 401 on both MCP and A2A instead of selecting a preferred carrier. Before upgrading, remove stale proxy/client aliases or send the same decoded token in every accepted carrier. This replaces the prior Authorization-wins/first-nonempty migration behavior documented by #720.
- types: Omitted optional boolean const fields now return None instead of True; callers must handle None and explicitly pass True when intended.
- server: Public A2A deployments now enforce the SDK Host and Origin policy by default. The default Host allowlist is loopback-only, so deployments serving a public hostname must configure allowed_hosts for their controlled public or proxy Host values before upgrading; otherwise requests including agent-card discovery return HTTP 421. A discovery/public URL does not itself grant Host trust. Configure browser allowed_origins separately when needed. Preserve fail-closed enforcement rather than trusting arbitrary inbound Host values.
- reporting: Reporting generation APIs and storage require authenticated caller ownership. Stop reporting readers, admission and workers for the documented maintenance migration and authoritative backfill; unmapped state and inherited work remain quarantined without automatic replay.
- signing: Direct brand.json signing-key resolvers require agent_url and select keys by canonical agent URL.
- accounts: Account task errors now raise typed buyer-setup exceptions, unknown natural references follow account_policy, and wholesale feed scope is required. ExplicitAccounts.resolve(None) returns None for public discovery. Migration guidance is in docs/account-lifecycle.md.
chore
- release: start SDK 9 beta series (827d80f)
refactor
- codegen: generated models are defined at adcp.types.domains.<domain>.<schema>, and adcp.types.generated_poc.* is now a deprecated alias of the same module objects (DeprecationWarning, removed in v10); migrate with the prefix rename adcp.types.generated_poc. -> adcp.types.domains. (3092340)
Features
- accounts: add provisioning-aware discovery and scoped feeds (#1288) (0499d6b)
- adagents: expose typed fetch errors and transport options (#1330) (a344195)
- auth: resolve non-bearer principals on both transports (#1328) (68345b5)
- decisioning: observe committed task lifecycle transitions (#1323) (9a70217)
- idempotency: commit business writes and replay in explicit reservations (#1322) (f4525ad)
- pg: lazily resolve decisioning stores on the serving loop (#1327) (5987c40)
- server: add explicit unauthenticated operational routes (#1336) (dfeb5f9)
- server: add typed MCP success text callbacks (#1337) (6e676cd)
- signing: publish the recovery classification the signing schema mandates (#1403) (86ae412), closes #1400
- types: adcp_version and adcp_major_version are plain str and int on AcceptProposalRequest, BuyProductsRequest, ControlMediaBuyRequest, DeclineProposalsRequest, ListProductsRequest, RefineProposalsRequest, RequestProposalsRequest and SyncReportingStatusRequest (drop .root), and every task request and response gains AdcpRequest or AdcpResponse as its first base (3092340)
- types: add statically typed pinned versioned bases (#1340) (8d27463)
- types: add the AdcpRequest and AdcpResponse markers, AdcpVersionEnvelope on adcp.types.protocol, and the missing Legacy* media-buy response names; LegacyFormatId now resolves to the generated format reference (3092340)
- types: emit a composing schema root as what it composes (#1353) (e5c2712)
- types: emit scalar schema roots as plain scalar subclasses (#1286) (9a70503)
- types: export shared legacy asset coercion helpers (#1334) (4a84082)
- types: format_kind and format_kinds are open str on every generated and canonical model and no value is refused; compare with == instead of
is CanonicalFormatKind.xand check the vocabulary with adcp.types.is_canonical_format_kind (3092340) - types: public canonical creative models are real subclasses of the generated classes they refine, and canonical_creative.pyi is deleted, so mypy now enforces previously hidden required fields (ListCreativesResponse requires query_summary and pagination) and generated validators now apply (CreativeManifest requires format_id or format_kind) (3092340)
- webhooks: add transactional PostgreSQL notification outbox (#1338) (a0fbee3)
- webhooks: prepare validated non-task notifications (#1335) (3d4df2b)
Bug Fixes
- accounts: restore 8.0 defaults behind opt-in strict modes for 8.1 (#1348) (3598d09)
- adagents: follow bounded ads.txt redirects with per-hop pins (#1332) (4c59734)
- adagents: normalize agent matching and expose listing lookup (#1329) (decbcdf)
- adagents: remove wall-clock sensitivity from two flaky adagents tests (#1408) (0d2e61d)
- auth: preserve outer principal on MCP anonymous path (#1326) (6bf9565)
- auth: unify duplicate credential policy across transports (#1325) (7f9b670)
- canonical-formats: accept a generated format reference, and name the parameter a refusal is about (#1376) (9c07724)
- ci: make SDK 14 storyboard lanes pass and gate merges (#1345) (a5d56a6)
- ci: repair bot credentials and scope release metadata validation (#1390) (d01636c)
- ci: use cached dependencies for isolated package builds (#1395) (59b4922)
- codegen: enforce root-level anyOf/oneOf required groups (#1368) (2224c78)
- codegen: keep the format-reference agent_url as the wire string (#1396) (197bcde)
- codegen: make a dead post-generation fix and a stale generated tree fail the build (#1374) (a5fe081)
- codegen: resolve structural pointer refs to the type they select (#1371) (6fa21d2)
- decisioning: serve account-scoped task polling and listing (#1320) (56fefd2)
- decisioning: support dict products and platform-owned property filtering (#1324) (3fd42a1)
- deps: raise dependency floors to the lowest installable working set (#1389) (91b0904), closes #1387
- idempotency: coalesce local retries before borrowing lock connections (#1317) (a76d81a)
- idempotency: recognize registered wrappers through outer decorators (#1315) (03da98a)
- reporting: isolate generations by authenticated caller (#1342) (096a637)
- reporting: preserve declared capabilities across lifecycle states (#1319) (6e8c3e2)
- reporting: translate installed service errors by recovery policy (#1316) (9dfc52c)
- router: advertise only declared optional implementations (#1321) (382954e)
- router: validate requests against resolved child annotations (#1318) (8a38b64)
- sdk: restore buyer compatibility and error diagnostics (#1285) (fa4f945)
- server: bind fresh MCP managers and endpoints for each lifespan (#1333) (a6e7673)
- server: enforce shared Host and Origin policy across HTTP transports (#1331) (44a07e6)
- signing: align agent resolution and publisher pins with AdCP 3.3 (#1312) (6677169)
- signing: close three step-1 header rules and export the precheck (#1369) (8f23329)
- signing: emit only the webhook taxonomy's codes from webhook verification (#1388) (9219573)
- signing: emit the spec WWW-Authenticate challenge from one place (#1372) (b4ff04d)
- signing: fetch resolver capabilities over the agent protocol (#1284) (5e243c9)
- signing: make agent_url optional with a fail-closed 8.0 fallback (#1350) (a083a19)
- signing: make REQUEST_TO_WEBHOOK_CODE the only webhook code decider (#1370) (885cbda)
- signing: report the discovery-chain code the spec assigns each resolver failure (#1373) (d8debc0)
- signing: ship the IP pin for httpx2 as well as httpx (#1378) (6f88af7)
- signing: stop
allow_privatefrom admitting IANA special-use ranges (#1377) (a287ee2) - tests: bound reporting factory work at hour boundaries (#1391) (9ca5a22)
- tests: isolate caller identity handler registration (#1344) (92b6994)
- types: defer adapters and prebuild models before freezing time (#1339) (357726e)
- types: derive the export surface from the generated modules (#1367) (8f989e3)
- types: name each export once in all (#1393) (d033c36)
- types: preserve omission of optional boolean constants (#1351) (63bfadb)
- types: restore opt-in reporting correlation on AdCP 3.2 (#1349) (48b1776)
- types: restore the composed base dropped from the canonical clone (#1341) (f4bdda7)
- validation: make the generated models agree with the bundled schema (#1375) (f07db30)
- validation: preserve wire version envelopes under unknown-field policies (#1314) (07b5d04)