@adcp/sdk 8.1.0-beta.6 → 8.1.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +12 -0
  2. package/dist/lib/conformance/oracle.d.ts.map +1 -1
  3. package/dist/lib/conformance/oracle.js +8 -1
  4. package/dist/lib/conformance/oracle.js.map +1 -1
  5. package/dist/lib/conformance/schemaArbitrary.js +135 -9
  6. package/dist/lib/conformance/schemaArbitrary.js.map +1 -1
  7. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  8. package/dist/lib/server/create-adcp-server.d.ts +5 -0
  9. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  10. package/dist/lib/server/create-adcp-server.js +41 -3
  11. package/dist/lib/server/create-adcp-server.js.map +1 -1
  12. package/dist/lib/server/decisioning/capabilities.d.ts +8 -0
  13. package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
  14. package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -1
  15. package/dist/lib/server/decisioning/proposal/dispatch.js +2 -0
  16. package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -1
  17. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  18. package/dist/lib/server/decisioning/runtime/from-platform.js +14 -1
  19. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  20. package/dist/lib/server/responses.d.ts +1 -1
  21. package/dist/lib/server/responses.d.ts.map +1 -1
  22. package/dist/lib/server/responses.js +5 -2
  23. package/dist/lib/server/responses.js.map +1 -1
  24. package/dist/lib/signing/types.d.ts +6 -0
  25. package/dist/lib/signing/types.d.ts.map +1 -1
  26. package/dist/lib/signing/types.js.map +1 -1
  27. package/dist/lib/signing/verifier.d.ts.map +1 -1
  28. package/dist/lib/signing/verifier.js +33 -4
  29. package/dist/lib/signing/verifier.js.map +1 -1
  30. package/dist/lib/testing/storyboard/compliance.d.ts +1 -0
  31. package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
  32. package/dist/lib/testing/storyboard/compliance.js +8 -2
  33. package/dist/lib/testing/storyboard/compliance.js.map +1 -1
  34. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  35. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  36. package/dist/lib/testing/storyboard/index.js +3 -2
  37. package/dist/lib/testing/storyboard/index.js.map +1 -1
  38. package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
  39. package/dist/lib/testing/storyboard/probes.js +3 -0
  40. package/dist/lib/testing/storyboard/probes.js.map +1 -1
  41. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  42. package/dist/lib/testing/storyboard/runner.js +294 -29
  43. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  44. package/dist/lib/testing/storyboard/types.d.ts +59 -0
  45. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  46. package/dist/lib/testing/storyboard/types.js.map +1 -1
  47. package/dist/lib/testing/storyboard/validations.d.ts +4 -3
  48. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
  49. package/dist/lib/testing/storyboard/validations.js +26 -2
  50. package/dist/lib/testing/storyboard/validations.js.map +1 -1
  51. package/dist/lib/types/activate-signal.d.ts +647 -0
  52. package/dist/lib/types/build-creative.d.ts +2105 -0
  53. package/dist/lib/types/calibrate-content.d.ts +675 -0
  54. package/dist/lib/types/check-governance.d.ts +619 -0
  55. package/dist/lib/types/comply-test-controller.d.ts +8428 -0
  56. package/dist/lib/types/core.generated.d.ts +180 -252
  57. package/dist/lib/types/core.generated.d.ts.map +1 -1
  58. package/dist/lib/types/core.generated.js +1 -1
  59. package/dist/lib/types/create-collection-list.d.ts +693 -0
  60. package/dist/lib/types/create-content-standards.d.ts +830 -0
  61. package/dist/lib/types/create-media-buy.d.ts +3374 -0
  62. package/dist/lib/types/create-property-list.d.ts +836 -0
  63. package/dist/lib/types/delete-collection-list.d.ts +497 -0
  64. package/dist/lib/types/delete-property-list.d.ts +497 -0
  65. package/dist/lib/types/get-account-financials.d.ts +624 -0
  66. package/dist/lib/types/get-adcp-capabilities.d.ts +2863 -0
  67. package/dist/lib/types/get-collection-list.d.ts +763 -0
  68. package/dist/lib/types/get-content-standards.d.ts +919 -0
  69. package/dist/lib/types/get-creative-delivery.d.ts +2219 -0
  70. package/dist/lib/types/get-creative-features.d.ts +1736 -0
  71. package/dist/lib/types/get-media-buy-artifacts.d.ts +864 -0
  72. package/dist/lib/types/get-media-buys.d.ts +1670 -0
  73. package/dist/lib/types/get-plan-audit-logs.d.ts +455 -0
  74. package/dist/lib/types/get-products.d.ts +4935 -0
  75. package/dist/lib/types/get-property-list.d.ts +874 -0
  76. package/dist/lib/types/get-signals.d.ts +986 -0
  77. package/dist/lib/types/list-accounts.d.ts +851 -0
  78. package/dist/lib/types/list-content-standards.d.ts +975 -0
  79. package/dist/lib/types/list-creative-formats.d.ts +3132 -0
  80. package/dist/lib/types/list-creatives.d.ts +2390 -0
  81. package/dist/lib/types/list-property-lists.d.ts +855 -0
  82. package/dist/lib/types/log-event.d.ts +373 -0
  83. package/dist/lib/types/per-tool-index.json +391 -0
  84. package/dist/lib/types/preview-creative.d.ts +1981 -0
  85. package/dist/lib/types/provide-performance-feedback.d.ts +218 -0
  86. package/dist/lib/types/report-plan-outcome.d.ts +433 -0
  87. package/dist/lib/types/report-usage.d.ts +579 -0
  88. package/dist/lib/types/schemas.generated.d.ts +127279 -125067
  89. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  90. package/dist/lib/types/schemas.generated.js +221 -293
  91. package/dist/lib/types/schemas.generated.js.map +1 -1
  92. package/dist/lib/types/si-get-offering.d.ts +259 -0
  93. package/dist/lib/types/si-initiate-session.d.ts +372 -0
  94. package/dist/lib/types/si-send-message.d.ts +300 -0
  95. package/dist/lib/types/si-terminate-session.d.ts +213 -0
  96. package/dist/lib/types/sync-accounts.d.ts +856 -0
  97. package/dist/lib/types/sync-audiences.d.ts +707 -0
  98. package/dist/lib/types/sync-catalogs.d.ts +766 -0
  99. package/dist/lib/types/sync-creatives.d.ts +2134 -0
  100. package/dist/lib/types/sync-event-sources.d.ts +665 -0
  101. package/dist/lib/types/sync-governance.d.ts +558 -0
  102. package/dist/lib/types/sync-plans.d.ts +979 -0
  103. package/dist/lib/types/update-collection-list.d.ts +697 -0
  104. package/dist/lib/types/update-content-standards.d.ts +847 -0
  105. package/dist/lib/types/update-media-buy.d.ts +3047 -0
  106. package/dist/lib/types/update-property-list.d.ts +840 -0
  107. package/dist/lib/types/validate-content-delivery.d.ts +722 -0
  108. package/dist/lib/types/validate-input.d.ts +1683 -0
  109. package/dist/lib/utils/response-schemas.js +1 -1
  110. package/dist/lib/utils/response-schemas.js.map +1 -1
  111. package/dist/lib/utils/response-unwrapper.d.ts.map +1 -1
  112. package/dist/lib/utils/response-unwrapper.js +18 -3
  113. package/dist/lib/utils/response-unwrapper.js.map +1 -1
  114. package/dist/lib/version.d.ts +3 -3
  115. package/dist/lib/version.js +3 -3
  116. package/examples/error-compliant-server.ts +1 -1
  117. package/examples/hello_seller_adapter_guaranteed.ts +8 -3
  118. package/examples/hello_seller_adapter_multi_tenant.ts +27 -23
  119. package/examples/hello_seller_adapter_non_guaranteed.ts +7 -3
  120. package/examples/hello_seller_adapter_proposal_mode.ts +22 -6
  121. package/examples/hello_signals_adapter_marketplace.ts +34 -3
  122. package/package.json +9 -2
@@ -0,0 +1,2863 @@
1
+ // AUTO-GENERATED — DO NOT EDIT.
2
+ // Per-tool .d.ts slice for `get_adcp_capabilities`. Built from the published
3
+ // `tools.generated.d.ts` + `core.generated.d.ts` + `enums.generated.d.ts`
4
+ // by `scripts/generate-per-tool-types.ts`.
5
+ //
6
+ // Self-contained: imports nothing from the broader SDK. Adopters who
7
+ // import only this slice pay a fraction of the tsc cost of pulling in
8
+ // `@adcp/sdk` root — useful when strict + skipLibCheck:false adopters
9
+ // hit memory pressure on the full surface.
10
+
11
+ /**
12
+ * Request payload for get_adcp_capabilities task. Protocol-level capability discovery that works across all AdCP protocols.
13
+ */
14
+ export interface GetAdCPCapabilitiesRequest {
15
+ /**
16
+ * Release-precision AdCP version (VERSION.RELEASE, e.g. "3.0", "3.1", "3.1-beta"). On a request: the buyer's release pin — the seller validates against its supported_versions and returns VERSION_UNSUPPORTED on cross-major mismatch, or downshifts to the highest supported release within the same major. On a response: the release the seller actually served — clients SHOULD validate the response against that release's schema, not against their pin. Patches are not negotiated; surface them as build_version on capabilities for operational visibility. When omitted, falls back to adcp_major_version (deprecated) or server default. Buyers SHOULD emit both adcp_version and adcp_major_version through 3.x to remain compatible with sellers that only read the legacy field. NORMALIZATION: SDKs that read full-semver values from bundle metadata (e.g. ComplianceIndex.published_version = "3.1.0-beta.1") MUST normalize to release-precision ("3.1-beta.1") before emitting on the wire — meta-field values are NOT valid wire values.
17
+ */
18
+ adcp_version?: string;
19
+ /**
20
+ * DEPRECATED in favor of adcp_version (release-precision string). Servers MUST continue to honor this field through 3.x. Removed in 4.0. Original semantics: the AdCP major version the buyer's payloads conform to. Sellers validate against their supported major_versions and return VERSION_UNSUPPORTED if unsupported. When omitted, the seller assumes its highest supported version.
21
+ */
22
+ adcp_major_version?: number;
23
+ /**
24
+ * Specific protocols to query capabilities for. If omitted, returns capabilities for all supported protocols.
25
+ */
26
+ protocols?: ('media_buy' | 'signals' | 'governance' | 'sponsored_intelligence' | 'creative')[];
27
+ context?: ContextObject;
28
+ ext?: ExtensionObject;
29
+ }
30
+
31
+ /**
32
+ * Response payload for get_adcp_capabilities task. Protocol-level capability discovery across all AdCP protocols. Each protocol has its own capability section.
33
+ */
34
+ export interface GetAdCPCapabilitiesResponse {
35
+ /**
36
+ * Session/conversation identifier for tracking related operations across multiple task invocations. Managed by the protocol layer to maintain conversational context. Distinct from `context` (per-request opaque echo, see below).
37
+ */
38
+ context_id?: string;
39
+ context?: ContextObject;
40
+ /**
41
+ * Unique identifier for tracking asynchronous operations. Present when a task requires extended processing time. Used to query task status and retrieve results when complete.
42
+ */
43
+ task_id?: string;
44
+ status: TaskStatus;
45
+ /**
46
+ * Human-readable summary of the task result. Provides natural language explanation of what happened, suitable for display to end users or for AI agent comprehension. Generated by the protocol layer based on the task response.
47
+ */
48
+ message?: string;
49
+ /**
50
+ * ISO 8601 timestamp when the response was generated. Useful for debugging, logging, cache validation, and tracking async operation progress.
51
+ */
52
+ timestamp?: string;
53
+ /**
54
+ * Set to true when this response was returned from the idempotency cache rather than from a fresh execution. Set to false (or omitted) when the request was executed fresh. Buyers use this to distinguish cached replays from new executions — matters for billing reconciliation, audit logs, state-machine routing (cached state-tracking fields are historical snapshots, not current state — re-read via the resource's read endpoint), and any downstream system that assumes exactly-once event semantics. From 3.1 onward, `replayed` MAY appear on responses to any request that resolved via the idempotency cache, including read tools — universal `idempotency_key` (see security.mdx §Idempotency) means the cache holds read responses too.
55
+ */
56
+ replayed?: boolean;
57
+ adcp_error?: Error;
58
+ push_notification_config?: PushNotificationConfig;
59
+ /**
60
+ * Governance context token issued by the account's governance agent during check_governance. Buyers attach it to governed purchase requests (media buys, rights acquisitions, signal activations, creative services); sellers persist it and include it on all subsequent governance calls for that action's lifecycle. An account binds to one governance agent (see sync_governance); governance is phased across `purchase` / `modification` / `delivery`, not partitioned across specialist agents, so the envelope carries a single token for the full lifecycle.
61
+ *
62
+ * Value format: governance agents MUST emit a compact JWS per the AdCP JWS profile (see Security — Signed Governance Context). Sellers MAY verify; sellers that do not verify MUST persist and forward the token unchanged. In 3.1 all sellers MUST verify. Non-JWS values from pre-3.0 governance agents are deprecated.
63
+ *
64
+ * This is the primary correlation key for audit and reporting across the governance lifecycle.
65
+ */
66
+ governance_context?: string;
67
+ /**
68
+ * Conceptual grouping for the task-specific response data defined by individual task response schemas (e.g., get-products-response.json, create-media-buy-response.json). `payload` is a documentary construct — it is NOT a required wire field, and its on-the-wire shape depends on transport (see Transport serialization below). Task response schemas declare body fields without wrapping them in a `payload` object; the wire representation places those body fields per transport convention. On MCP the body fields appear as siblings of envelope fields at the root of the tool response; on A2A they appear inside `task.artifacts[0].parts[].DataPart`; on REST they appear at the root of the JSON body.
69
+ */
70
+ payload?: {};
71
+ /**
72
+ * Release-precision AdCP version (VERSION.RELEASE, e.g. "3.0", "3.1", "3.1-beta"). On a request: the buyer's release pin — the seller validates against its supported_versions and returns VERSION_UNSUPPORTED on cross-major mismatch, or downshifts to the highest supported release within the same major. On a response: the release the seller actually served — clients SHOULD validate the response against that release's schema, not against their pin. Patches are not negotiated; surface them as build_version on capabilities for operational visibility. When omitted, falls back to adcp_major_version (deprecated) or server default. Buyers SHOULD emit both adcp_version and adcp_major_version through 3.x to remain compatible with sellers that only read the legacy field. NORMALIZATION: SDKs that read full-semver values from bundle metadata (e.g. ComplianceIndex.published_version = "3.1.0-beta.1") MUST normalize to release-precision ("3.1-beta.1") before emitting on the wire — meta-field values are NOT valid wire values.
73
+ */
74
+ adcp_version?: string;
75
+ /**
76
+ * DEPRECATED in favor of adcp_version (release-precision string). Servers MUST continue to honor this field through 3.x. Removed in 4.0. Original semantics: the AdCP major version the buyer's payloads conform to. Sellers validate against their supported major_versions and return VERSION_UNSUPPORTED if unsupported. When omitted, the seller assumes its highest supported version.
77
+ */
78
+ adcp_major_version?: number;
79
+ /**
80
+ * Core AdCP protocol information
81
+ */
82
+ adcp: {
83
+ /**
84
+ * DEPRECATED in favor of `supported_versions` (release-precision strings). Servers MUST continue to emit this field through 3.x for backwards compatibility. Removed in 4.0. Original semantics: AdCP major versions supported by this seller. Major versions indicate breaking changes.
85
+ */
86
+ major_versions: number[];
87
+ /**
88
+ * Release-precision (VERSION.RELEASE) AdCP versions this seller speaks. Authoritative for buyer-side release pinning — buyers SHOULD declare `adcp_version` (release-precision string) on each request. Sellers downshift to the highest supported release ≤ the buyer's pin within the same major; cross-major mismatch returns VERSION_UNSUPPORTED. Pre-release tags (e.g. `"3.1-beta"`) hang off release.
89
+ */
90
+ supported_versions?: string[];
91
+ /**
92
+ * Optional advisory metadata: full semver build identifier of the seller's deployment — MAJOR.MINOR.PATCH plus optional pre-release and build-metadata segments per semver §9–§10. Patches are not part of the wire contract — semver patch by definition introduces no contract change — but surfacing the build helps buyers triage incidents and bug reports against a specific seller deployment lineage. Buyers MUST NOT use this field for negotiation; use `supported_versions` (release-precision) instead.
93
+ * @pattern ^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$
94
+ */
95
+ build_version?: string;
96
+ /**
97
+ * Idempotency semantics for mutating requests. Sellers MUST declare whether they honor idempotency_key replay protection so buyers can reason about safe retry behavior. Modeled as a discriminated union on the supported boolean so that code generators produce two named types (IdempotencySupported, IdempotencyUnsupported) with the replay_ttl_seconds invariant enforced at the type level — draft-07 if/then would be dropped by most generators (openapi-typescript, zod-to-json-schema, datamodel-code-generator pre-0.25, quicktype). Clients MUST NOT assume a default — a seller without this declaration is non-compliant and should be treated as unsafe for retry-sensitive operations.
98
+ */
99
+ idempotency: IdempotencySupported | IdempotencyUnsupported;
100
+ };
101
+ /**
102
+ * AdCP protocols this agent supports. Each value both (a) declares which tools the agent implements and (b) commits the agent to pass the baseline compliance storyboard at /compliance/{version}/protocols/{protocol}/ (with snake_case → kebab-case path mapping, e.g. media_buy → /compliance/.../protocols/media-buy/). The `measurement` protocol is in development — currently scoped to `get_adcp_capabilities` for catalog discovery; additional measurement tasks (reporting, attribution, etc.) and a baseline storyboard land in subsequent minors. Compliance testing support is declared separately via the `compliance_testing` capability block (below), not as a protocol claim.
103
+ */
104
+ supported_protocols: ('media_buy' | 'signals' | 'governance' | 'sponsored_intelligence' | 'creative' | 'brand' | 'measurement')[];
105
+ /**
106
+ * Account management capabilities. Describes how accounts are established, what billing models are supported, and whether an account is required before browsing products.
107
+ */
108
+ account?: {
109
+ /**
110
+ * Whether the seller requires operator-level credentials. When true (explicit accounts), operators authenticate independently with the seller and the buyer discovers accounts via list_accounts. When false (default, implicit accounts), the seller trusts the agent's identity claims — the agent authenticates once and declares brands/operators via sync_accounts.
111
+ */
112
+ require_operator_auth?: boolean;
113
+ /**
114
+ * OAuth authorization endpoint for obtaining operator-level credentials. Present when the seller supports OAuth for operator authentication. The agent directs the operator to this URL to authenticate and obtain a bearer token. If absent and require_operator_auth is true, operators obtain credentials out-of-band (e.g., seller portal, API key).
115
+ */
116
+ authorization_endpoint?: string;
117
+ /**
118
+ * Billing models this seller supports. operator: seller invoices the operator (agency or brand buying direct). agent: agent consolidates billing. advertiser: seller invoices the advertiser directly, even when a different operator places orders on their behalf. The buyer must pass one of these values in sync_accounts.
119
+ */
120
+ supported_billing: BillingParty[];
121
+ /**
122
+ * Whether an account reference is required for get_products. When true, the buyer must establish an account before browsing products. When false (default), the buyer can browse products without an account — useful for price comparison and discovery before committing to a seller.
123
+ */
124
+ required_for_products?: boolean;
125
+ /**
126
+ * Whether this seller exposes the `get_account_financials` task for querying account-level financial status (spend, credit, invoices). Acts as a **pre-call discriminator** — buyers MUST consult this field before issuing `get_account_financials`; when `false` (or absent), sellers MAY reject the call with an `UNSUPPORTED_FEATURE` / `OPERATION_NOT_SUPPORTED` error. Companion pattern to `creative.bills_through_adcp` (issue #2881) — both fields let buyers gate optional capability calls on a single declared boolean rather than probing for support. Only applicable to operator-billed accounts; sellers using buyer-billed flows omit or set to `false`.
127
+ */
128
+ account_financials?: boolean;
129
+ /**
130
+ * Whether this seller supports sandbox accounts for testing. Buyers can provision a sandbox account via sync_accounts with sandbox: true, and all requests using that account_id will be treated as sandbox — no real platform calls or spend.
131
+ */
132
+ sandbox?: boolean;
133
+ };
134
+ /**
135
+ * Media-buy protocol capabilities. Expected when media_buy is in supported_protocols. Sellers declaring media_buy should also include account with supported_billing.
136
+ */
137
+ media_buy?: {
138
+ /**
139
+ * Pricing models this seller supports across its product portfolio. Buyers can use this for pre-flight filtering before querying individual products. Individual products may support a subset of these models.
140
+ */
141
+ supported_pricing_models?: PricingModel[];
142
+ /**
143
+ * Buying modes this seller supports on get_products. 'brief' (semantic discovery driven by the brief) is universally supported and implicit. 'wholesale' (raw wholesale product feed enumeration — caller omits brief and the seller returns the full priced product feed, paginated) is opt-in and SHOULD be declared explicitly so buyers can probe before issuing wholesale calls. 'refine' (iterate on prior products/proposals) is implicit when the seller declares supports_proposals or otherwise honors the refine array. Sellers MAY declare ['brief', 'wholesale'] to signal wholesale support; absent declaration is treated as ['brief'] for wholesale-feed probing purposes and sellers MAY return INVALID_REQUEST for wholesale calls they do not support. Symmetric with signals.discovery_modes.
144
+ */
145
+ buying_modes?: ('brief' | 'wholesale' | 'refine')[];
146
+ /**
147
+ * How this seller delivers reporting data to buyers. Polling via get_media_buy_delivery is always available as a baseline regardless of this field. This array declares additional push-based delivery methods the seller supports. 'webhook': seller pushes to buyer-provided URL (configured per buy via reporting_webhook). 'offline': seller pushes batch files to a cloud storage bucket (seller-provisioned per account via reporting_bucket on the account object). When absent, only polling is available.
148
+ */
149
+ reporting_delivery_methods?: ('webhook' | 'offline')[];
150
+ /**
151
+ * Cloud storage protocols this seller supports for offline file delivery. Only meaningful when reporting_delivery_methods includes 'offline'. Buyers express a protocol preference in sync_accounts; the seller provisions the account's reporting_bucket using a supported protocol.
152
+ */
153
+ offline_delivery_protocols?: CloudStorageProtocol[];
154
+ /**
155
+ * Whether this seller commits to the proposal lifecycle on get_products: when called with buying_mode: 'brief' the seller will return at least one entry in proposals[]; when called with buying_mode: 'refine' + action: 'finalize' the seller will transition a proposal from draft to committed. A declaration of true is a commitment the seller will be graded against, not just a feature flag — sellers that decline a brief on policy grounds still owe a structured proposal-shaped rejection rather than an empty proposals[]. Most guaranteed-deal sellers (premium pubs, broadcast, CTV) declare true; auction-based PG, retail SKU, and quoted-rate direct-buy flows declare false. When false or absent, the seller serves products directly without proposal abstraction; conformance runners skip proposal-lifecycle storyboards.
156
+ */
157
+ supports_proposals?: boolean;
158
+ /**
159
+ * Where this seller surfaces dependency-resource impairments (creative rejected post-approval, audience suspended, catalog item withdrawn, event source insufficient, property depublished) to buyers. Non-exclusive: a seller mirroring impairments on both the buy snapshot AND firing webhooks declares `["snapshot", "webhook"]` (the common case for premium guaranteed sellers). Each value names one surface where buyers can observe an impairment:
160
+ *
161
+ * - **`snapshot`** — seller propagates resource transitions into `media_buy.health` and `media_buy.impairments[]` on the next `get_media_buys` read. The `impairment.coherence` compliance assertion grades this surface; storyboards that exercise it (`media_buy_seller/dependency_impairment`, `media_buy_seller/dependency_impairment_cardinality`) require `"snapshot"` to be declared, else they grade `not_applicable`.
162
+ * - **`webhook`** — seller fires `notification-type: impairment` webhooks (configured via `push_notification_config`). Sellers declaring `"webhook"` MUST satisfy the persistent-channel webhook contract for the impairment event type. A seller declaring `["webhook"]` without `"snapshot"` is webhook-only — buyers reconcile state from the push channel alone, and snapshot-coherence storyboards grade `not_applicable`.
163
+ * - **`out_of_band`** — seller propagates via channels outside the AdCP protocol surface entirely (email to trafficker, separate dashboard, partner-specific notification feed). Long-tail and enterprise-bundled platforms commonly use this when impairment workflows are managed in human channels. Sellers declaring only `["out_of_band"]` are not graded by snapshot or webhook compliance — their bar is the offline agreement, not a protocol assertion. If a seller has impairment data in their API under a non-AdCP field name (a mapping gap, not truly out-of-band), they SHOULD document the mapping rather than declare `out_of_band` — the spec's gap, not the seller's posture, is what `out_of_band` legitimately covers.
164
+ *
165
+ * Default: `["snapshot"]` when absent (preserves the existing snapshot-coherence contract for sellers that don't declare). Empty array `[]` is invalid (`minItems: 1`) — omit the field to inherit the default rather than declaring no surfaces. Pick the surfaces that honestly describe where buyers will see impairments on this agent. Mixing is normative — `["snapshot", "webhook"]` is the documented common case; `["snapshot", "webhook", "out_of_band"]` is valid for sellers that ship all three surfaces (rare but legal). See lifecycle.mdx § Compliance for the per-surface contract.
166
+ */
167
+ propagation_surfaces?: ('snapshot' | 'webhook' | 'out_of_band')[];
168
+ features?: MediaBuyFeatures;
169
+ /**
170
+ * Technical execution capabilities for media buying
171
+ */
172
+ execution?: {
173
+ /**
174
+ * Trusted Match Protocol (TMP) support. Presence of this object indicates the seller has TMP infrastructure deployed. Check individual products via get_products for per-product TMP capabilities.
175
+ */
176
+ trusted_match?: {
177
+ /**
178
+ * Surface types this seller supports via TMP.
179
+ */
180
+ surfaces?: ('website' | 'mobile_app' | 'ctv_app' | 'desktop_app' | 'dooh' | 'podcast' | 'radio' | 'streaming_audio' | 'ai_assistant')[];
181
+ };
182
+ /**
183
+ * Deprecated. Legacy AXE integrations. Use trusted_match for new integrations.
184
+ */
185
+ axe_integrations?: string[];
186
+ /**
187
+ * Creative specification support
188
+ */
189
+ creative_specs?: {
190
+ /**
191
+ * VAST versions supported for video creatives
192
+ */
193
+ vast_versions?: string[];
194
+ /**
195
+ * MRAID versions supported for rich media mobile creatives
196
+ */
197
+ mraid_versions?: string[];
198
+ /**
199
+ * VPAID support for interactive video ads
200
+ */
201
+ vpaid?: boolean;
202
+ /**
203
+ * SIMID support for interactive video ads
204
+ */
205
+ simid?: boolean;
206
+ };
207
+ /**
208
+ * Targeting capabilities. If declared true/supported, buyer can use these targeting parameters and seller MUST honor them.
209
+ */
210
+ targeting?: {
211
+ /**
212
+ * Country-level targeting using ISO 3166-1 alpha-2 codes
213
+ */
214
+ geo_countries?: boolean;
215
+ /**
216
+ * Region/state-level targeting using ISO 3166-2 codes (e.g., US-NY, GB-SCT)
217
+ */
218
+ geo_regions?: boolean;
219
+ /**
220
+ * Metro area targeting. Properties indicate which classification systems are supported.
221
+ */
222
+ geo_metros?: {
223
+ nielsen_dma?: boolean;
224
+ uk_itl1?: boolean;
225
+ uk_itl2?: boolean;
226
+ eurostat_nuts2?: boolean;
227
+ };
228
+ /**
229
+ * Postal area targeting. Properties indicate which postal code systems are supported.
230
+ */
231
+ geo_postal_areas?: {
232
+ us_zip?: boolean;
233
+ us_zip_plus_four?: boolean;
234
+ gb_outward?: boolean;
235
+ gb_full?: boolean;
236
+ ca_fsa?: boolean;
237
+ ca_full?: boolean;
238
+ de_plz?: boolean;
239
+ fr_code_postal?: boolean;
240
+ au_postcode?: boolean;
241
+ ch_plz?: boolean;
242
+ at_plz?: boolean;
243
+ };
244
+ /**
245
+ * Age restriction capabilities for compliance (alcohol, gambling)
246
+ */
247
+ age_restriction?: {
248
+ /**
249
+ * Whether seller supports age restrictions
250
+ */
251
+ supported?: boolean;
252
+ /**
253
+ * Age verification methods this seller supports
254
+ */
255
+ verification_methods?: AgeVerificationMethod[];
256
+ };
257
+ /**
258
+ * Whether seller supports language targeting (ISO 639-1 codes)
259
+ */
260
+ language?: boolean;
261
+ /**
262
+ * Keyword targeting capabilities. Presence indicates support for targeting_overlay.keyword_targets and keyword_targets_add/remove in update_media_buy.
263
+ */
264
+ keyword_targets?: {
265
+ /**
266
+ * Match types this seller supports for keyword targets. Sellers must reject goals with unsupported match types.
267
+ */
268
+ supported_match_types: MatchType[];
269
+ };
270
+ /**
271
+ * Negative keyword capabilities. Presence indicates support for targeting_overlay.negative_keywords and negative_keywords_add/remove in update_media_buy.
272
+ */
273
+ negative_keywords?: {
274
+ /**
275
+ * Match types this seller supports for negative keywords. Sellers must reject goals with unsupported match types.
276
+ */
277
+ supported_match_types: MatchType[];
278
+ };
279
+ /**
280
+ * Proximity targeting capabilities from arbitrary coordinates via targeting_overlay.geo_proximity.
281
+ */
282
+ geo_proximity?: {
283
+ /**
284
+ * Whether seller supports simple radius targeting (distance circle from a point)
285
+ */
286
+ radius?: boolean;
287
+ /**
288
+ * Whether seller supports travel time isochrone targeting (requires a routing engine)
289
+ */
290
+ travel_time?: boolean;
291
+ /**
292
+ * Whether seller supports pre-computed GeoJSON geometry (buyer provides the polygon)
293
+ */
294
+ geometry?: boolean;
295
+ /**
296
+ * Transport modes supported for travel_time isochrones. Only relevant when travel_time is true.
297
+ */
298
+ transport_modes?: TransportMode[];
299
+ };
300
+ };
301
+ };
302
+ /**
303
+ * Audience targeting capabilities. Presence of this object indicates the seller supports audience targeting, including sync_audiences and audience_include/audience_exclude in targeting overlays.
304
+ */
305
+ audience_targeting?: {
306
+ /**
307
+ * PII-derived identifier types accepted for audience matching. Buyers should only send identifiers the seller supports.
308
+ */
309
+ supported_identifier_types: ('hashed_email' | 'hashed_phone')[];
310
+ /**
311
+ * Whether the seller accepts the buyer's CRM/loyalty ID as a matchable identifier. Only applicable when the seller operates a closed ecosystem with a shared ID namespace (e.g., a retailer matching against their loyalty program). When true, buyers can include platform_customer_id values in AudienceMember.identifiers for matching against the seller's identity graph. Reporting on matched platform_customer_ids typically requires a clean room or the seller's own reporting surface.
312
+ */
313
+ supports_platform_customer_id?: boolean;
314
+ /**
315
+ * Universal ID types accepted for audience matching (MAIDs, RampID, UID2, etc.). MAID support varies significantly by platform — check this field before sending uids with type: maid.
316
+ */
317
+ supported_uid_types?: UIDType[];
318
+ /**
319
+ * Minimum matched audience size required for targeting. Audiences below this threshold will have status: too_small. Varies by platform (100–1000 is typical).
320
+ * @minimum 1
321
+ */
322
+ minimum_audience_size: number;
323
+ /**
324
+ * Expected matching latency range in hours after upload. Use to calibrate polling cadence and set appropriate expectations before configuring push_notification_config.
325
+ */
326
+ matching_latency_hours?: {
327
+ /**
328
+ * @minimum 0
329
+ */
330
+ min?: number;
331
+ /**
332
+ * @minimum 0
333
+ */
334
+ max?: number;
335
+ };
336
+ };
337
+ /**
338
+ * Optimization metrics this seller can support on at least one of their products. Seller-level rollup of product-level metric_optimization.supported_metrics declarations (core/product.json). Buyers SHOULD filter their requested optimization goals against this list before submitting briefs. Sellers MUST keep this in sync with their product catalog — if no products support a metric, it must not appear here. Omitting this field means the seller declares no specific guarantees about which metrics they support; buyers should fall back to per-product inspection of metric_optimization.supported_metrics.
339
+ */
340
+ supported_optimization_metrics?: ('clicks' | 'views' | 'completed_views' | 'viewed_seconds' | 'attention_seconds' | 'attention_score' | 'engagements' | 'follows' | 'saves' | 'profile_visits' | 'reach')[];
341
+ /**
342
+ * Seller-level conversion tracking capabilities. Presence of this object indicates the seller supports sync_event_sources and log_event for conversion event tracking.
343
+ */
344
+ conversion_tracking?: {
345
+ /**
346
+ * Whether this seller can deduplicate conversion events across multiple event sources within a single goal. When true, the seller honors the deduplication semantics in optimization_goals event_sources arrays — the same event_id from multiple sources counts once. When false or absent, buyers should use a single event source per goal; multi-source arrays will be treated as first-source-wins. Most social platforms cannot deduplicate across independently-managed pixel and CAPI sources.
347
+ */
348
+ multi_source_event_dedup?: boolean;
349
+ /**
350
+ * Whether the seller can attribute conversions to specific creatives within a package and surface that breakdown via media_buy_deliveries[].by_package[].by_creative[].conversions in get_media_buy_delivery. Defaults to false when omitted. Sellers that report conversions only at the line / package / placement / campaign granularity (retail-media, MMP-mediated mobile, CTV performance) declare false (or omit) and the per-creative scenario grades not_applicable for them. Sellers that surface ad-level conversion attribution (most social platforms) declare true and the scenario asserts the breakdown is populated end-to-end. Defaults to false to preserve backward compatibility.
351
+ */
352
+ per_creative_attribution?: boolean;
353
+ /**
354
+ * Event types this seller can track and attribute. If omitted, all standard event types are supported.
355
+ */
356
+ supported_event_types?: EventType[];
357
+ /**
358
+ * Event-goal target kinds this seller can compute against. Buyers should only submit event-kind optimization goals whose target.kind is listed here — sellers MUST reject goals with unlisted target kinds. When omitted, only target-less event goals (maximize conversion count within budget) are guaranteed; sellers MAY accept specific target kinds but buyers should not rely on it. Named to parallel `metric_optimization.supported_targets` at the product level — same concept (which target kinds are supported), one at seller-capability granularity and one at product granularity.
359
+ */
360
+ supported_targets?: ('cost_per' | 'per_ad_spend' | 'maximize_value')[];
361
+ /**
362
+ * Universal ID types accepted for user matching
363
+ */
364
+ supported_uid_types?: UIDType[];
365
+ /**
366
+ * Hashed PII types accepted for user matching. Buyers must hash before sending (SHA-256, normalized).
367
+ */
368
+ supported_hashed_identifiers?: ('hashed_email' | 'hashed_phone')[];
369
+ /**
370
+ * Action sources this seller accepts events from
371
+ */
372
+ supported_action_sources?: ActionSource[];
373
+ /**
374
+ * Attribution windows available from this seller. Single-element arrays indicate fixed windows; multi-element arrays indicate configurable options the buyer can choose from via attribution_window on optimization goals.
375
+ */
376
+ attribution_windows?: {
377
+ event_type?: EventType;
378
+ /**
379
+ * Available post-click attribution windows (e.g. [{"interval": 7, "unit": "days"}])
380
+ */
381
+ post_click: Duration[];
382
+ /**
383
+ * Available post-view attribution windows (e.g. [{"interval": 1, "unit": "days"}])
384
+ */
385
+ post_view?: Duration[];
386
+ }[];
387
+ };
388
+ /**
389
+ * Frequency capping capabilities. Presence of this object indicates the seller honors targeting.frequency_cap on packages and MUST reject caps it cannot enforce rather than silently dropping them. Buyers SHOULD inspect supported_per_units and supported_window_units before submitting caps; sellers without these sub-fields populated MAY accept any reach-unit / duration-unit combination they can enforce. Per-product overrides (for sellers with mixed addressable/non-addressable inventory) are a likely follow-up — file a separate RFC if needed.
390
+ */
391
+ frequency_capping?: {
392
+ /**
393
+ * Entity granularities the seller can enforce caps against. Values from the reach-unit enum. Omit to indicate all reach-unit values are supported.
394
+ */
395
+ supported_per_units?: ReachUnit[];
396
+ /**
397
+ * Duration units the seller supports for frequency cap windows. Values must match the duration.json unit enum (e.g., 'hours', 'days', 'campaign'). Omit to indicate all duration units are supported.
398
+ */
399
+ supported_window_units?: string[];
400
+ };
401
+ /**
402
+ * Content standards implementation details. Presence of this object indicates the seller supports content_standards configuration including sampling rates and category filtering. Gives buyers pre-buy visibility into local evaluation and artifact delivery capabilities.
403
+ */
404
+ content_standards?: {
405
+ /**
406
+ * Whether the seller runs a local evaluation model. When false, all artifacts will have local_verdict: 'unevaluated' and the failures_only filter on get_media_buy_artifacts is not useful.
407
+ */
408
+ supports_local_evaluation?: boolean;
409
+ /**
410
+ * Channels for which the seller can provide content artifacts. Helps buyers understand which parts of a mixed-channel buy will have content standards coverage.
411
+ */
412
+ supported_channels?: MediaChannel[];
413
+ /**
414
+ * Whether the seller supports push-based artifact delivery via artifact_webhook configured at buy creation time.
415
+ */
416
+ supports_webhook_delivery?: boolean;
417
+ };
418
+ /**
419
+ * Information about the seller's media inventory portfolio. Expected for media_buy sellers — buyers use this to understand inventory coverage and verify authorization via adagents.json.
420
+ */
421
+ portfolio?: {
422
+ /**
423
+ * Publisher domains this seller is authorized to represent. Buyers should fetch each publisher's adagents.json for property definitions.
424
+ */
425
+ publisher_domains: string[];
426
+ /**
427
+ * Primary advertising channels in this portfolio
428
+ */
429
+ primary_channels?: MediaChannel[];
430
+ /**
431
+ * Primary countries (ISO 3166-1 alpha-2) where inventory is concentrated
432
+ */
433
+ primary_countries?: string[];
434
+ /**
435
+ * Markdown-formatted description of the inventory portfolio
436
+ * @maxLength 5000
437
+ */
438
+ description?: string;
439
+ /**
440
+ * Advertising content policies, restrictions, and guidelines
441
+ * @maxLength 10000
442
+ */
443
+ advertising_policies?: string;
444
+ };
445
+ };
446
+ /**
447
+ * Signals protocol capabilities. Only present if signals is in supported_protocols.
448
+ */
449
+ signals?: {
450
+ /**
451
+ * Data provider domains this signals agent is authorized to resell. Buyers should fetch each data provider's adagents.json for signal catalog definitions and to verify authorization.
452
+ */
453
+ data_provider_domains?: string[];
454
+ /**
455
+ * Discovery modes this signals agent supports on get_signals. 'brief' (default — every signals agent supports this): semantic discovery driven by signal_spec or signal_ids. 'wholesale': raw wholesale signals feed enumeration — caller omits signal_spec/signal_ids and the agent returns its full priced signals feed, paginated, scoped by filters/account/destinations/countries. Agents that do not declare 'wholesale' MAY return INVALID_REQUEST for wholesale calls. Absent declaration is treated as ['brief'].
456
+ */
457
+ discovery_modes?: ('brief' | 'wholesale')[];
458
+ /**
459
+ * Optional signals features supported
460
+ */
461
+ features?: {
462
+ /**
463
+ * Supports signals from data provider catalogs with structured signal_id references
464
+ */
465
+ catalog_signals?: boolean;
466
+ [k: string]: boolean | undefined;
467
+ };
468
+ };
469
+ /**
470
+ * Governance protocol capabilities. Only present if governance is in supported_protocols. Governance agents provide property and creative data like compliance scores, brand safety ratings, sustainability metrics, and creative quality assessments.
471
+ */
472
+ governance?: {
473
+ /**
474
+ * Trailing window (in days) over which this governance agent aggregates committed spend when evaluating dollar-valued thresholds (reallocation_threshold, human_review triggers, registry-policy floors). Required for fragmentation defense: without aggregation, a buyer can split a single large spend into many sub-threshold commits across plans / task surfaces / time and bypass every dollar-gated escalation. Aggregation is keyed on (buyer_agent, seller_agent, account_id) and spans all spend-commit task types. Upper bound 365 represents a one-year trailing window (fiscal-year alignment with grace); governance agents needing longer scopes negotiate via operator sign-off, not this capability. No schema default: absence of this field indicates the governance agent has not committed to any aggregation window and buyers MUST assume per-commit evaluation only (the fragmentation attack surface is open). A declared value of 30 is a common starting point but is not implied by omission. Buyers depending on a specific window for compliance MUST check this capability before relying on aggregation semantics — an agent declaring 7 days does not defend against fragmentation spread across a 30-day quarter-end push.
475
+ * @minimum 1
476
+ * @maximum 365
477
+ */
478
+ aggregation_window_days?: number;
479
+ /**
480
+ * Property features this governance agent can evaluate. Each feature describes a score, rating, or certification the agent can provide for properties.
481
+ */
482
+ property_features?: {
483
+ /**
484
+ * Unique identifier for this feature (e.g., 'consent_quality', 'coppa_certified', 'carbon_score')
485
+ */
486
+ feature_id: string;
487
+ /**
488
+ * Data type: 'binary' for yes/no, 'quantitative' for numeric scores, 'categorical' for enum values
489
+ */
490
+ type: 'binary' | 'quantitative' | 'categorical';
491
+ /**
492
+ * For quantitative features, the valid range
493
+ */
494
+ range?: {
495
+ /**
496
+ * Minimum value
497
+ */
498
+ min: number;
499
+ /**
500
+ * Maximum value
501
+ */
502
+ max: number;
503
+ };
504
+ /**
505
+ * For categorical features, the valid values
506
+ */
507
+ categories?: string[];
508
+ /**
509
+ * Human-readable description of what this feature measures
510
+ */
511
+ description?: string;
512
+ /**
513
+ * URL to documentation explaining how this feature is calculated or measured. Helps buyers understand and compare methodologies across vendors.
514
+ */
515
+ methodology_url?: string;
516
+ }[];
517
+ /**
518
+ * Creative features this governance agent can evaluate. Each feature describes a score, rating, or assessment the agent can provide for creatives (e.g., security scanning, creative quality, content categorization).
519
+ */
520
+ creative_features?: {
521
+ /**
522
+ * Unique identifier for this feature (e.g., 'auto_redirect', 'brand_consistency', 'iab_casinos_gambling')
523
+ */
524
+ feature_id: string;
525
+ /**
526
+ * Data type: 'binary' for yes/no, 'quantitative' for numeric scores, 'categorical' for enum values
527
+ */
528
+ type: 'binary' | 'quantitative' | 'categorical';
529
+ /**
530
+ * For quantitative features, the valid range
531
+ */
532
+ range?: {
533
+ /**
534
+ * Minimum value
535
+ */
536
+ min: number;
537
+ /**
538
+ * Maximum value
539
+ */
540
+ max: number;
541
+ };
542
+ /**
543
+ * For categorical features, the valid values
544
+ */
545
+ categories?: string[];
546
+ /**
547
+ * Human-readable description of what this feature measures
548
+ */
549
+ description?: string;
550
+ /**
551
+ * URL to documentation explaining how this feature is calculated or measured.
552
+ */
553
+ methodology_url?: string;
554
+ }[];
555
+ };
556
+ /**
557
+ * Sponsored Intelligence protocol capabilities. Only present if sponsored_intelligence is in supported_protocols. SI agents handle conversational brand experiences.
558
+ */
559
+ sponsored_intelligence?: {
560
+ /**
561
+ * SI agent endpoint configuration
562
+ */
563
+ endpoint: {
564
+ /**
565
+ * Available protocol transports. Hosts select based on their capabilities.
566
+ */
567
+ transports: {
568
+ /**
569
+ * Protocol transport type
570
+ */
571
+ type: 'mcp' | 'a2a';
572
+ /**
573
+ * Agent endpoint URL for this transport
574
+ */
575
+ url: string;
576
+ }[];
577
+ /**
578
+ * Preferred transport when host supports multiple
579
+ */
580
+ preferred?: 'mcp' | 'a2a';
581
+ };
582
+ capabilities: SICapabilities;
583
+ /**
584
+ * URL to brand.json with colors, fonts, logos, tone
585
+ */
586
+ brand_url?: string;
587
+ };
588
+ /**
589
+ * Brand protocol capabilities. Only present if brand is in supported_protocols. Brand agents provide identity data (logos, colors, tone, assets) and optionally rights clearance for licensable content (talent, music, stock media).
590
+ */
591
+ brand?: {
592
+ /**
593
+ * Supports get_rights and acquire_rights for rights discovery and clearance
594
+ */
595
+ rights?: boolean;
596
+ /**
597
+ * Types of rights available through this agent
598
+ */
599
+ right_types?: RightType[];
600
+ /**
601
+ * Rights uses available across this agent's roster
602
+ */
603
+ available_uses?: RightUse[];
604
+ /**
605
+ * LLM/generation providers this agent can issue credentials for
606
+ */
607
+ generation_providers?: string[];
608
+ /**
609
+ * Description of the agent's brand protocol capabilities
610
+ * @maxLength 5000
611
+ */
612
+ description?: string;
613
+ };
614
+ /**
615
+ * Creative protocol capabilities. Only present if creative is in supported_protocols.
616
+ */
617
+ creative?: {
618
+ /**
619
+ * When true, this creative agent can process briefs with compliance requirements (required_disclosures, prohibited_claims) and will validate that disclosures can be satisfied by the target format.
620
+ */
621
+ supports_compliance?: boolean;
622
+ /**
623
+ * When true, this agent hosts a creative library and supports list_creatives and creative_id references in build_creative. Creative agents with a library should also implement the accounts protocol (sync_accounts / list_accounts) so buyers can establish access.
624
+ */
625
+ has_creative_library?: boolean;
626
+ /**
627
+ * When true, this agent can generate creatives from natural language briefs via build_creative. The buyer provides a message with creative direction, and the agent produces a manifest with generated assets. When false, build_creative only supports transformation or library retrieval.
628
+ */
629
+ supports_generation?: boolean;
630
+ /**
631
+ * When true, this agent can transform or resize existing manifests via build_creative. The buyer provides a creative_manifest and a target_format_id, and the agent adapts the creative to the new format.
632
+ */
633
+ supports_transformation?: boolean;
634
+ /**
635
+ * Canonical-formats path: format declarations describing which canonical formats this creative agent can produce via `build_creative`. Each entry uses the same `ProductFormatDeclaration` shape as a product's inline `format_options[i]` — `format_kind` discriminator + `params` (canonical's parameter schema including `slots`, dimensions, durations, codecs, character limits, platform_extensions, tracking_extensions). Replaces the v1 `list_creative_formats` discovery surface for creative agents.
636
+ */
637
+ supported_formats?: {
638
+ /**
639
+ * Stable identifier for this format declaration within the agent (e.g., 'audiostack_audio_30s'). Optional but recommended for declarations that may be referenced over time.
640
+ */
641
+ capability_id?: string;
642
+ format: ProductFormatDeclaration;
643
+ }[];
644
+ /**
645
+ * When true, this creative agent bills through the AdCP rate-card surface: list_creatives returns pricing_options when include_pricing=true with an authenticated account, build_creative populates pricing_option_id and vendor_cost on the response, and report_usage accepts records against the rate card. When false or absent, the agent bills out of band (flat license, SaaS contract, bundled enterprise agreement) and buyers should skip pricing fields and tolerate report_usage returning accepted: 0 with errors carrying BILLING_OUT_OF_BAND. A pre-call discriminator so buyer agents can route across many creative agents without first establishing an account to probe pricing.
646
+ */
647
+ bills_through_adcp?: boolean;
648
+ /**
649
+ * Optional. The AdCP canonical-formats catalog version this agent's runtime is built against (e.g., `3.1`, `3.2.0`). Lets buyer SDKs detect canonical-catalog skew between their generated types and the seller's actual support. SDKs MAY declare the version they were generated against (typically the AdCP version they ship for); when seller and SDK versions disagree, SDKs SHOULD soft-warn rather than fail (the open-enum semantics on `canonical-format-kind.json` make unknown canonicals safe to retain, so skew is not a hard error — it just means the older side might not understand newer canonical values). Omitted by sellers who haven't yet generated against a versioned catalog; absence is interpreted as the AdCP version advertised by the broader capabilities response.
650
+ * @pattern ^\d+\.\d+(\.\d+)?$
651
+ */
652
+ canonical_catalog_version?: string;
653
+ };
654
+ /**
655
+ * RFC 9421 HTTP Signatures support for incoming requests. Optional in 3.0 — capability-advertised so counterparties can opt into signing selectively. Required for spend-committing operations in 4.0 (the next breaking-changes accumulation window). The full profile is defined in docs/building/implementation/security.mdx (Signed Requests (Transport Layer)).
656
+ */
657
+ request_signing?: {
658
+ /**
659
+ * Whether this agent verifies RFC 9421 signatures on incoming requests. When true, signatures present on requests are validated per the AdCP request-signing profile. When false or absent, signatures are ignored (requests are bearer-authenticated only).
660
+ */
661
+ supported: boolean;
662
+ /**
663
+ * Policy for content-digest coverage in request signatures. 'required': signers MUST cover content-digest (body is bound to the signature); body-unbound signatures rejected with request_signature_components_incomplete. 'forbidden': signers MUST NOT cover content-digest; body-bound signatures rejected with request_signature_components_unexpected. This is an opt-out for the narrow case of legacy infrastructure that cannot preserve body bytes. 'either' (default): signer chooses per-request; verifier accepts both covered and uncovered forms. 'required' is recommended for spend-committing operations in production; 4.0 recommends 'required' for those operations.
664
+ */
665
+ covers_content_digest?: 'required' | 'forbidden' | 'either';
666
+ /**
667
+ * AdCP protocol operation names (e.g., 'create_media_buy') for which this agent rejects unsigned requests with request_signature_required. Not MCP tool names, A2A skill names, or any transport-specific rename — verifiers MUST NOT accept operation names that are not defined by the AdCP protocol spec. JSON-RPC protocol method names like `tasks/cancel` belong in `protocol_methods_required_for`, not here. Empty in 3.0 by default; sellers populate selectively during per-counterparty pilots. In 4.0 this list MUST include all spend-committing operations the agent supports (create_media_buy, acquire_*, etc.). Counterparties MUST sign any listed operation. Every operation listed MUST also appear in `supported_for` (an operation can't be required without being supported); see `x-adcp-validation`.
668
+ */
669
+ required_for?: string[];
670
+ /**
671
+ * AdCP protocol operation names for which this agent verifies signatures when present and logs failures but does NOT reject the request. Used as a shadow-mode bridge between supported_for and required_for: the verifier surfaces failure rates in monitoring before flipping an operation to required. Precedence: required_for > warn_for > supported_for. An operation in required_for ignores warn_for. Counterparties SHOULD sign operations in warn_for; verifiers MUST NOT reject if the signature is missing or invalid. An operation MUST NOT appear in both `warn_for` and `required_for`; see `x-adcp-validation`.
672
+ */
673
+ warn_for?: string[];
674
+ /**
675
+ * AdCP protocol operation names for which this agent verifies signatures when present but does not require them. Counterparties SHOULD sign operations in this list. Typically a superset of required_for and warn_for.
676
+ */
677
+ supported_for?: string[];
678
+ /**
679
+ * JSON-RPC protocol method names (e.g., 'tasks/cancel', 'tasks/get') for which this agent verifies signatures when present. Disjoint from `supported_for`, which carries AdCP tool names only. Counterparties SHOULD sign listed methods. The `tasks/*` family enumerated here matches the A2A 0.3.0 task-lifecycle methods (§7.x); future protocol additions extend this list, not `supported_for`. Items MUST be wire-format JSON-RPC method strings (containing `/`); plain AdCP tool names belong in `supported_for`.
680
+ */
681
+ protocol_methods_supported_for?: string[];
682
+ /**
683
+ * Protocol method names for which this agent verifies signatures when present and logs failures but does NOT reject. Shadow-mode bridge between `protocol_methods_supported_for` and `protocol_methods_required_for`, mirroring `warn_for` semantics in the AdCP-tool namespace. An item MUST NOT appear in both `protocol_methods_warn_for` and `protocol_methods_required_for`; see `x-adcp-validation`.
684
+ */
685
+ protocol_methods_warn_for?: string[];
686
+ /**
687
+ * JSON-RPC protocol method names for which this agent rejects unsigned requests with `request_signature_required`. Separate namespace from `required_for` (which carries AdCP tool names) so verifiers and storyboard runners don't conflate the two — an AdCP tool name and an A2A method name could in principle collide as bare strings, but the protocol_methods_* bucket binds the match against the JSON-RPC `method` field, not the `tools/call` `params.name`. Every method listed MUST also appear in `protocol_methods_supported_for`; see `x-adcp-validation`.
688
+ */
689
+ protocol_methods_required_for?: string[];
690
+ };
691
+ /**
692
+ * RFC 9421 webhook-signature support for outbound webhook callbacks (top-level peer of request_signing). Declares which AdCP webhook-signing profile version and algorithms this agent produces on delivery, and whether it supports the legacy HMAC-SHA256 fallback for receivers that have not yet adopted RFC 9421. See docs/building/implementation/webhooks.mdx.
693
+ */
694
+ webhook_signing?: {
695
+ /**
696
+ * Whether this agent signs outbound webhooks with the AdCP RFC 9421 webhook profile. When false or absent, webhooks are delivered with legacy Bearer or HMAC-SHA256 auth only and receivers MUST NOT expect a Signature header. When the seller advertises mutating-webhook emission (i.e., `media_buy.reporting_delivery_methods` includes `webhook`, `media_buy.content_standards.supports_webhook_delivery` is true, or `wholesale_feed_webhooks.supported` is true), this MUST be `true` — emitting state-changing webhooks unsigned is a downgrade vector that lets an on-path attacker forge delivery callbacks. See `x-adcp-validation`.
697
+ */
698
+ supported: boolean;
699
+ /**
700
+ * Identifier of the webhook-signing profile version the agent emits. Value MUST match the `tag=` parameter emitted in the RFC 9421 `Signature-Input` header (see docs/building/implementation/webhooks.mdx) so receivers can statically validate the declared profile against the on-wire tag. Closed enum; future profile revisions will extend this enum in a follow-up schema bump.
701
+ */
702
+ profile?: 'adcp/webhook-signing/v1';
703
+ /**
704
+ * Signature algorithms this agent uses on outbound webhooks. 3.0 profile permits 'ed25519' and 'ecdsa-p256-sha256' only; other values are reserved for future profile versions and MUST NOT be emitted under adcp/webhook-signing/v1.
705
+ */
706
+ algorithms?: ('ed25519' | 'ecdsa-p256-sha256')[];
707
+ /**
708
+ * Whether this agent will fall back to HMAC-SHA256 on the legacy push_notification_config.authentication or accounts[].notification_configs[].authentication paths for receivers that have not adopted RFC 9421. Deprecated; removed in AdCP 4.0.
709
+ */
710
+ legacy_hmac_fallback?: boolean;
711
+ };
712
+ /**
713
+ * Operator identity posture — trust-root pointer (`brand_json_url`) plus key-scoping and compromise-response controls the agent operates. `brand_json_url` is **load-bearing** for signature verification: when the agent declares any signing posture (`request_signing.supported_for`/`required_for` non-empty, `webhook_signing.supported === true`, or any `key_origins` subfield), `brand_json_url` MUST be present (storyboard-enforced in 3.x; schema-required in 4.0). Verifiers use it to bootstrap from the agent URL to the operator's brand.json (and from there to signing keys); see [security.mdx §Discovering an agent's signing keys](https://adcontextprotocol.org/docs/building/by-layer/L1/security#discovering-an-agents-signing-keys-via-brand_json_url). The remaining fields (`per_principal_key_isolation`, `key_origins`, `compromise_notification`) are advisory and receivers use them to reason about blast radius and revocation latency at onboarding. Empty-object semantics: `identity: {}` means "posture block present but no posture claimed" — schema-valid but advisory-neutral and receivers MUST treat it as equivalent to omitting the block, **except** that an agent declaring a signing posture elsewhere in the response with an empty `identity` MUST be rejected by storyboard runners as missing `brand_json_url`.
714
+ */
715
+ identity?: {
716
+ /**
717
+ * HTTPS URL of the operator's brand.json (typically `https://{operator-domain}/.well-known/brand.json`). Trust-root pointer for this agent's signing keys. See [security.mdx §Discovering an agent's signing keys via `brand_json_url`](https://adcontextprotocol.org/docs/building/by-layer/L1/security#discovering-an-agents-signing-keys-via-brand_json_url) for the verifier algorithm and `x-adcp-validation` for structured constraints. Distinct from `sponsored_intelligence.brand_url`, which is a rendering pointer for SI agent visuals — verifiers MUST use this field for key discovery and MUST NOT fall back to `sponsored_intelligence.brand_url` as a trust-root pointer.
718
+ * @pattern ^https:\/\/
719
+ */
720
+ brand_json_url?: string;
721
+ /**
722
+ * When true, this multi-principal operator scopes signing keys per-principal so a single principal's key compromise does not silently re-scope across principals served by the same operator. `kid` values remain opaque to verifiers per RFC 7517; any operator-side naming convention (e.g., `{operator}:{principal}:{key_version}`) is internal bookkeeping and MUST NOT be parsed by verifiers. See docs/building/understanding/security-model.mdx.
723
+ */
724
+ per_principal_key_isolation?: boolean;
725
+ /**
726
+ * Map of signing-key purpose → publishing origin, so counterparties can verify origin separation (e.g., governance keys served from a separate origin than transport/webhook keys) at onboarding. Absent means the operator has not declared a separation scheme; receivers SHOULD assume shared-origin. Every purpose listed MUST have a corresponding signing posture declared elsewhere — `request_signing` requires non-empty `request_signing.supported_for`/`required_for`/`protocol_methods_supported_for`/`protocol_methods_required_for`; `webhook_signing` requires `webhook_signing.supported === true` — otherwise the consistency check at signature-verification time has nothing to anchor against. See `x-adcp-validation` and docs/building/implementation/security.mdx §Origin separation.
727
+ */
728
+ key_origins?: {
729
+ /**
730
+ * Origin (scheme + host) serving the governance-signing JWKS.
731
+ */
732
+ governance_signing?: string;
733
+ /**
734
+ * Origin (scheme + host) serving the request-signing JWKS.
735
+ */
736
+ request_signing?: string;
737
+ /**
738
+ * Origin (scheme + host) serving the webhook-signing JWKS.
739
+ */
740
+ webhook_signing?: string;
741
+ /**
742
+ * Origin (scheme + host) serving the TMP-signing JWKS, when this operator participates in TMP.
743
+ */
744
+ tmp_signing?: string;
745
+ };
746
+ /**
747
+ * Whether this agent emits the `identity.compromise_notification` webhook event on key revocation due to known or suspected compromise (as opposed to scheduled rotation). Subscribers use this to bound the window between compromise detected and verifiers converging on revocation. See docs/building/implementation/webhooks.mdx §identity.compromise_notification.
748
+ */
749
+ compromise_notification?: {
750
+ /**
751
+ * Whether this agent emits `identity.compromise_notification` events.
752
+ */
753
+ emits?: boolean;
754
+ /**
755
+ * Whether this agent subscribes to `identity.compromise_notification` events from counterparties it verifies signatures from.
756
+ */
757
+ accepts?: boolean;
758
+ };
759
+ };
760
+ /**
761
+ * Measurement capability block. Presence indicates this agent computes one or more quantitative metrics about ad delivery, exposure, or effect, and is willing to be discovered as a measurement vendor. Returns metric definitions (this surface), not pricing/coverage (negotiated via `measurement_terms` on `create_media_buy`) or live values (returned per buy via `vendor_metric_values`). Modeled as a capability block (like `compliance_testing` and `webhook_signing`) rather than a `supported_protocols` value because measurement agents have one surface — this catalog — not a tool-set with mandatory tasks. AAO crawls each measurement agent's `metrics[]` on a TTL to populate the federated cross-vendor index. Same self-describing pattern as `governance.property_features[]`: agents own the catalog; the registry aggregates.
762
+ */
763
+ measurement?: {
764
+ /**
765
+ * Metrics this agent computes. Each entry is identified by `metric_id` within the vendor's vocabulary; the canonical reference everywhere a measurement value appears (`committed_metrics`, `vendor_metric_values`, `missing_metrics`) is the tuple `(vendor.domain, vendor.brand_id, metric_id)`.
766
+ */
767
+ metrics: {
768
+ metric_id: VendorMetricID;
769
+ /**
770
+ * Optional URI pointing at the published standard this metric IMPLEMENTS (e.g., IAB Attention Measurement Guidelines, MRC Viewable Impression Measurement, GARM emissions framework). Distinct from `accreditations[]` — `standard_reference` is what the metric is built against; `accreditations[]` is third-party certification that the implementation actually conforms. Buyer agents normalizing across vendors SHOULD apply the AdCP URL canonicalization rules before comparing — vendors implementing the same standard MAY use different URL forms for the same canonical document.
771
+ */
772
+ standard_reference?: string;
773
+ /**
774
+ * Third-party accreditations this metric holds (MRC, ARF, JIC, ABC, BARB, AGOF, etc.). Distinct from `standard_reference`: a metric can implement a standard without being independently accredited. Buyers asking 'is this MRC-accredited?' SHOULD check this array, not just `standard_reference`. Each entry names the accrediting body and optionally pins a certification ID, validity date, and evidence URL.
775
+ */
776
+ accreditations?: {
777
+ /**
778
+ * Accrediting organization — open string (the global landscape includes MRC, ARF, ABC, BARB, JICWEBS, AGOF, JIC bodies in many markets). Use the canonical short name where one exists.
779
+ */
780
+ accrediting_body: string;
781
+ /**
782
+ * Optional identifier for the certification in the accrediting body's records (when one exists; many bodies do not issue stable IDs).
783
+ */
784
+ certification_id?: string;
785
+ /**
786
+ * Optional ISO 8601 date when the current accreditation expires. Buyers MAY treat post-expiry data as un-accredited. Absence means the vendor does not assert an expiry — buyers SHOULD verify currency at the accrediting body's directory.
787
+ * @format date
788
+ */
789
+ valid_until?: string;
790
+ /**
791
+ * Optional URL pointing at the accrediting body's public listing for this certification (the buyer's path to verify the claim independently).
792
+ */
793
+ evidence_url?: string;
794
+ }[];
795
+ /**
796
+ * Unit of the metric value when reported via `vendor_metric_values.value` (e.g., `score`, `seconds`, `persons`, `gCO2e`, `lift_percent`, `USD`). Buyers SHOULD render the unit alongside the value rather than computing units locally; sellers populating `vendor_metric_values.unit` MUST match this declaration when present.
797
+ */
798
+ unit?: string;
799
+ /**
800
+ * Human-readable description of what this metric measures and any relevant methodology notes. Surfaced in buyer-agent UX when explaining the metric to humans.
801
+ */
802
+ description?: string;
803
+ /**
804
+ * URL to the vendor's full methodology documentation for this metric. Buyers SHOULD link or fetch this when human review of the methodology is in scope (compliance, RFP review, accreditation audit). Field name mirrors `governance.property_features[].methodology_url`.
805
+ */
806
+ methodology_url?: string;
807
+ /**
808
+ * Optional version identifier (semver, ISO date, or vendor-defined version string) for the methodology this metric currently implements. When present, buyer agents pin the contracted version on `committed_metrics` so silent vendor methodology changes are detectable; absence means the vendor does not version their methodology and buyers MUST treat any change as untracked.
809
+ */
810
+ methodology_version?: string;
811
+ ext?: ExtensionObject;
812
+ }[];
813
+ };
814
+ /**
815
+ * Compliance testing capabilities. The presence of this block declares that the agent supports deterministic testing via comply_test_controller for lifecycle state machine validation. Omit the block entirely if the agent does not support compliance testing.
816
+ */
817
+ compliance_testing?: {
818
+ /**
819
+ * Compliance testing scenarios this agent supports. Must be non-empty — at least one scenario. Callers can also use comply_test_controller with scenario: 'list_scenarios' to discover supported scenarios at runtime.
820
+ */
821
+ scenarios: ('force_creative_status' | 'force_account_status' | 'force_media_buy_status' | 'force_session_status' | 'simulate_delivery' | 'simulate_budget_spend')[];
822
+ };
823
+ /**
824
+ * Optional — specialized compliance claims this agent supports. Values MUST be kebab-case enum IDs (e.g., 'creative-generative', 'sales-non-guaranteed'). An agent that implements a specialism's tools but omits its ID from this array will receive 'No applicable tracks found' from the compliance runner — tracks for that specialism are not evaluated even if every tool works. Omitting the field means the agent declares no specialism claims (it still passes the universal + domain-baseline storyboards implied by supported_protocols). Each specialism maps to a storyboard bundle at /compliance/{version}/specialisms/{id}/ that the AAO compliance runner executes to verify the claim. Each specialism rolls up to one of the protocols in supported_protocols — the runner rejects a specialism claim whose parent protocol is missing. Only list specialisms your agent actually implements — the AAO Verified badge enumerates which specialisms were demonstrably passed.
825
+ */
826
+ specialisms?: AdCPSpecialism[];
827
+ /**
828
+ * Extension namespaces this agent supports. Buyers can expect meaningful data in ext.{namespace} fields on responses from this agent. Extension schemas are published in the AdCP extension registry.
829
+ */
830
+ extensions_supported?: string[];
831
+ /**
832
+ * Experimental AdCP surfaces this agent implements. A surface is experimental when its schema carries x-status: experimental and the working group has not yet frozen it. Sellers that implement any experimental surface MUST list its feature id here. Buyers inspect this array before relying on experimental surfaces — a seller that does not list a surface is asserting it does not implement it. Experimental surfaces MAY break between any two 3.x releases with at least 6 weeks notice; the full contract is in docs/reference/experimental-status.
833
+ */
834
+ experimental_features?: string[];
835
+ /**
836
+ * Conditional-fetch token capabilities for get_products and get_signals. Independent of wholesale feed webhooks: an agent MAY support cheap version probes via if_wholesale_feed_version without pushing change payloads (and vice versa). When supported is true, the agent returns wholesale_feed_version on every get_products / get_signals response and honors if_wholesale_feed_version on subsequent requests. When absent or supported is false, callers MAY still send if_wholesale_feed_version — pre-3.1 agents that ignore it just return the full payload (correct, just inefficient). Pre-flight declaration here lets buyers fast-path which agents to bother caching versions for. See get_products / get_signals 'Wholesale feed versioning' sections.
837
+ */
838
+ wholesale_feed_versioning?: {
839
+ /**
840
+ * Whether the agent returns wholesale_feed_version on responses and honors if_wholesale_feed_version on requests. When absent, treated as false; buyers MAY still probe (the field-presence detection path) but cannot pre-flight-decide.
841
+ */
842
+ supported: boolean;
843
+ /**
844
+ * Whether the agent tracks pricing_version independently of wholesale_feed_version. When true, the agent returns both tokens and honors if_pricing_version separately — useful for rate-card sweeps that don't change product and signal metadata. When false or absent, the agent collapses both into wholesale_feed_version; callers SHOULD NOT send if_pricing_version (it will be ignored and may produce INVALID_REQUEST when sent without if_wholesale_feed_version per the dependencies rule).
845
+ */
846
+ pricing_version_separate?: boolean;
847
+ /**
848
+ * Whether the agent ever returns cache_scope: 'account' (i.e., publishes per-account overlays distinct from the public rate card). When true, buyers MUST be prepared to maintain account-overlay caches alongside the public layer. When false or absent, all responses are cache_scope: 'public' regardless of whether account was provided — the agent's rate card is universal. Confidentiality note: declaring true advertises that the agent runs custom-pricing deals (low-grade market-posture signal); agents preferring not to disclose this MAY omit the field and let consumers detect-on-call via cache_scope on response.
849
+ */
850
+ cache_scope_account?: boolean;
851
+ };
852
+ /**
853
+ * ISO 8601 timestamp of when capabilities were last updated. Buyers can use this for cache invalidation.
854
+ * @format date-time
855
+ */
856
+ last_updated?: string;
857
+ /**
858
+ * Task-specific errors and warnings
859
+ */
860
+ errors?: Error[];
861
+ ext?: ExtensionObject;
862
+ /**
863
+ * Per-agent wholesale product-feed and wholesale signals-feed webhook capabilities. Declared by sales agents (products) and signals agents (signals). When supported is true, consumers can register sync_accounts.accounts[].notification_configs[] entries for product.* / signal.* / wholesale_feed.bulk_change and receive the actual change payload in each webhook. This is distinct from buyer-provided feeds managed by sync_catalogs. Consumers use get_products / get_signals with if_wholesale_feed_version as the repair and reconciliation path after missed or distrusted webhooks. See specs/wholesale-feed-webhooks.md. Webhook emission MUST apply the same caller/account authorization and scope predicate as the corresponding wholesale read; agents unable to guarantee per-principal filtering MUST NOT declare supported: true. Capability consistency: agents listing product.* event types MUST declare and support get_products with media_buy.buying_modes including wholesale; agents listing signal.* event types MUST declare and support get_signals with signals.discovery_modes including wholesale; agents listing wholesale_feed.bulk_change MUST have at least one of those wholesale repair paths and MUST only emit bulk-change payloads for affected_entity_type values backed by a declared repair path.
864
+ */
865
+ wholesale_feed_webhooks?: {
866
+ /**
867
+ * Whether this agent can push wholesale feed change payloads through account-level sync_accounts.accounts[].notification_configs[]. When false or absent, consumers fall back to wholesale polling, optionally with if_wholesale_feed_version probes.
868
+ */
869
+ supported: boolean;
870
+ /**
871
+ * Wholesale feed webhook event types this agent can emit. Sales agents emit product.* events. Signals agents emit signal.* events. Agents that are both can emit both event families. Agents listing product.* event types MUST declare and support get_products with media_buy.buying_modes including wholesale. Agents listing signal.* event types MUST declare and support get_signals with signals.discovery_modes including wholesale. wholesale_feed.bulk_change tells consumers to repair by re-reading the affected wholesale feed via get_products and/or get_signals; agents listing it MUST have at least one of those wholesale repair paths and MUST only emit bulk-change payloads for affected_entity_type values backed by a declared repair path.
872
+ */
873
+ event_types?: ('product.created' | 'product.updated' | 'product.priced' | 'product.removed' | 'signal.created' | 'signal.updated' | 'signal.priced' | 'signal.removed' | 'wholesale_feed.bulk_change')[];
874
+ };
875
+ }
876
+
877
+ /**
878
+ * Where the conversion event originated
879
+ */
880
+ export type ActionSource = 'website' | 'app' | 'offline' | 'phone_call' | 'chat' | 'email' | 'in_store' | 'system_generated' | 'other';
881
+
882
+ /**
883
+ * Specialized capability claims an agent can make. Each specialism maps to a compliance storyboard bundle published at /compliance/{version}/specialisms/{id}/. An agent asserts specialisms it supports in get_adcp_capabilities; the AAO compliance runner executes the matching storyboards to verify the claim.
884
+ */
885
+ export type AdCPSpecialism = 'audience-sync' | 'brand-rights' | 'collection-lists' | 'content-standards' | 'creative-ad-server' | 'creative-generative' | 'creative-template' | 'governance-aware-seller' | 'governance-delivery-monitor' | 'governance-spend-authority' | 'property-lists' | 'sales-broadcast-tv' | 'sales-catalog-driven' | 'sales-guaranteed' | 'sales-non-guaranteed' | 'sales-proposal-mode' | 'sales-social' | 'signal-marketplace' | 'signal-owned' | 'signed-requests' | 'sponsored-intelligence';
886
+
887
+ /**
888
+ * Methods for verifying user age for compliance. Does not include 'inferred' as it is not accepted for regulatory compliance.
889
+ */
890
+ export type AgeVerificationMethod = 'facial_age_estimation' | 'id_document' | 'digital_id' | 'credit_card' | 'world_id';
891
+
892
+ export interface AgentPlacementFormatDeclaration {
893
+ format_kind: 'agent_placement';
894
+ params: CanonicalFormatAgentPlacementAISurfaceSponsoredPlacement;
895
+ }
896
+
897
+ /**
898
+ * Legacy authentication schemes for the webhook auth block. Bearer: token sent in Authorization header. HMAC-SHA256: legacy shared-secret signing. Both are deprecated; new integrations SHOULD omit the authentication block and use the RFC 9421 webhook signing profile (applicable on schemas where authentication is optional). Removed in AdCP 4.0.
899
+ */
900
+ export type AuthenticationScheme = 'Bearer' | 'HMAC-SHA256';
901
+
902
+ /**
903
+ * Who is invoiced on this account. See billing_entity for the invoiced party's business details.
904
+ */
905
+ export type BillingParty = 'operator' | 'agent' | 'advertiser';
906
+
907
+ /**
908
+ * **3.2-track canonical.** The structural shape (algorithmic composition + brand-context input + optional offering/landing_page) is captured here so adopters can declare against it in 3.1 catalogs, but the **mention-level tracking contract is intentionally underspecified for 3.1**: no normative macro vocabulary, no postback shape, no cross-surface dedup model. Adopters claiming `agent_placement` in 3.1 ship private tracking integrations and SHOULD set `runtime_status: 'preview'` or `'declared_only'` on the declaration; buyer agents MUST treat agent_placement attribution as adapter-defined until the 3.2 tracking-macro spec lands. The canonical promotes to a normatively-buyer-callable surface in 3.2 (or later) once the tracking contract is specified.
909
+ *
910
+ * Sponsored placement integrated into an AI-surface's response to a user. Buyer supplies a `BrandRef` (resolving brand.json for context), an optional `offering_ref` to focus the mention on a specific offering, and an optional `landing_page_url` the surface MAY attach as a citation. The surface (LLM, voice assistant, sponsored-search ranker) composes a natural-language mention, sponsored card, or audio snippet within its response to a user query. **Composition is algorithmic** — the agent chooses phrasing and presentation. Output asset_type varies by surface: `text` for chat UIs and sponsored search snippets; `audio` (synthesized) for voice assistants; `card` for structured AI-surface result cards. Tracking model: mention-level impression + attribution events; per-mention id keys back to brand and offering — but see the 3.2-track note above; the wire shape of these events is not yet specified. Distinct from `si_chat` (which is the user-converses-with-brand's-agent pattern — brand owns the conversational surface) and from `sponsored_placement` (retail-media catalog-driven). Parallels `sponsored_placement` structurally: both are surface-composed placements; agent_placement is for AI/agentic surfaces, sponsored_placement is for retail media.
911
+ */
912
+ export interface CanonicalFormatAgentPlacementAISurfaceSponsoredPlacement {
913
+ /**
914
+ * Marked experimental at 3.1 GA: the canonical's tracking model (mention-level impression + attribution, postback shape, cross-surface dedup) is intentionally underspecified for 3.1. Adopters claiming `agent_placement` ship private tracking integrations; buyer agents MUST treat attribution as adapter-defined until the 3.2 tracking-macro spec lands. Promotion to non-experimental gated on the 3.2 tracking-contract spec.
915
+ */
916
+ experimental?: unknown;
917
+ /**
918
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
919
+ */
920
+ deprecated?: boolean;
921
+ /**
922
+ * Inherently new in v2 — AI-surface sponsored mentions weren't expressible as v1 named formats. SDKs MUST NOT emit `FORMAT_PROJECTION_FAILED` for products using this canonical; the v1-unreachability is structural.
923
+ */
924
+ v1_translatable?: unknown;
925
+ /**
926
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
927
+ */
928
+ since_version?: string;
929
+ /**
930
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
931
+ */
932
+ migration_target_version?: string;
933
+ /**
934
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
935
+ */
936
+ composition_model?: 'deterministic' | 'algorithmic';
937
+ /**
938
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
939
+ */
940
+ provenance_required?: boolean;
941
+ /**
942
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
943
+ *
944
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
945
+ */
946
+ platform_extensions?: PlatformExtensionReference[];
947
+ /**
948
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
949
+ *
950
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
951
+ */
952
+ synthesis_nondeterministic?: boolean;
953
+ /**
954
+ * agent_placement has minimal buyer-shipped slots — the surface composes the rendered output from brand context (resolved via the manifest's top-level `brand` BrandRef) plus optional offering_ref and landing_page_url assets. None of these assets are rendered verbatim by the buyer; the agent chooses how to use them.
955
+ */
956
+ slots?: unknown;
957
+ /**
958
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
959
+ */
960
+ production_window_business_days?: number;
961
+ /**
962
+ * How the surface presents the mention. `text` = inline text (chat, search snippet). `audio` = TTS-synthesized voice. `card` = structured card with optional image + text.
963
+ */
964
+ output_modality?: 'text' | 'audio' | 'card';
965
+ /**
966
+ * For text output: maximum length of the surface-composed mention text.
967
+ * @minimum 1
968
+ */
969
+ max_mention_length_chars?: number;
970
+ /**
971
+ * For audio output: maximum duration of the spoken mention in milliseconds.
972
+ * @minimum 1
973
+ */
974
+ max_mention_duration_ms?: number;
975
+ /**
976
+ * Whether the product accepts an offering reference (specific product/service to promote within the mention) in addition to brand context.
977
+ */
978
+ supports_offering_reference?: boolean;
979
+ /**
980
+ * Whether the surface attaches a landing page URL to the mention (citation, learn-more link).
981
+ */
982
+ supports_landing_page_url?: boolean;
983
+ /**
984
+ * **Advisory only.** Buyer-declared brand-voice preferences the surface SHOULD honor (e.g., ['formal', 'no_superlatives']). LLM/agentic surfaces have no protocol-level mechanism to verify enforcement — adopters that need hard guarantees should rely on brand.json voice declarations and post-mention review rather than this field. Future revisions may tie this to a structured tone vocabulary; for now treat as free-text guidance.
985
+ */
986
+ tone_constraints?: string[];
987
+ /**
988
+ * Whether the surface must include an explicit sponsorship disclosure label.
989
+ */
990
+ disclosure_required?: boolean;
991
+ }
992
+
993
+ /**
994
+ * DAAST-tag-delivered audio creative (audio analog of VAST). Slot: `daast_tag` (daast asset, URL or inline XML). Tracking model: DAAST events inherent to the spec — `impression`, `firstQuartile`, `midpoint`, `thirdQuartile`, `complete`, `start`, `pause`, `resume`, `mute`, `unmute`, `clickTracking`, `error`. Distinct from `audio_hosted` (direct file with external tracking).
995
+ */
996
+ export interface CanonicalFormatDAASTAudio {
997
+ /**
998
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
999
+ *
1000
+ * Three drivers of `experimental: true`:
1001
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1002
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1003
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1004
+ *
1005
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1006
+ */
1007
+ experimental?: boolean;
1008
+ /**
1009
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1010
+ */
1011
+ deprecated?: boolean;
1012
+ /**
1013
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
1014
+ *
1015
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
1016
+ */
1017
+ v1_translatable?: boolean;
1018
+ /**
1019
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1020
+ */
1021
+ since_version?: string;
1022
+ /**
1023
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1024
+ */
1025
+ migration_target_version?: string;
1026
+ /**
1027
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1028
+ */
1029
+ composition_model?: 'deterministic' | 'algorithmic';
1030
+ /**
1031
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1032
+ */
1033
+ provenance_required?: boolean;
1034
+ /**
1035
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1036
+ *
1037
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1038
+ */
1039
+ platform_extensions?: PlatformExtensionReference[];
1040
+ /**
1041
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1042
+ *
1043
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1044
+ */
1045
+ synthesis_nondeterministic?: boolean;
1046
+ /**
1047
+ * Default slots for audio_daast canonical. Buyer ships a DAAST tag (URL or inline XML, 1.0 or 1.1) plus an optional clickthrough URL. Tracking events are inherent to DAAST and don't require explicit slots.
1048
+ */
1049
+ slots?: unknown;
1050
+ /**
1051
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1052
+ */
1053
+ production_window_business_days?: number;
1054
+ daast_version?: '1.0' | '1.1';
1055
+ /**
1056
+ * [min, max] duration in milliseconds. **Precedence**: `duration_ms_exact` takes precedence when both ship. SDKs SHOULD lint a warning when both fields ship.
1057
+ */
1058
+ duration_ms_range?: number[];
1059
+ /**
1060
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship.
1061
+ * @minimum 1
1062
+ */
1063
+ duration_ms_exact?: number;
1064
+ linear_required?: boolean;
1065
+ /**
1066
+ * @minimum 0
1067
+ */
1068
+ max_wrapper_depth?: number;
1069
+ ssl_required?: boolean;
1070
+ companion_image_required?: boolean;
1071
+ }
1072
+
1073
+ /**
1074
+ * Third-party-served display tag (JS, iframe, or 1×1 redirect). The buyer's adserver hosts the creative; the seller calls the tag URL at impression time. Slot: `tag_url` (url asset with appropriate `url_type`). Tracking model: opaque to seller — third party serves and measures. Click tracking via redirect URL substitution using universal_macros. Distinct from `image` (static asset hosted by seller) and `html5` (zip bundle hosted by seller).
1075
+ */
1076
+ export type CanonicalFormatDisplayTag = SizeModeMutex & {
1077
+ /**
1078
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
1079
+ *
1080
+ * Three drivers of `experimental: true`:
1081
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1082
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1083
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1084
+ *
1085
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1086
+ */
1087
+ experimental?: boolean;
1088
+ /**
1089
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1090
+ */
1091
+ deprecated?: boolean;
1092
+ /**
1093
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
1094
+ *
1095
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
1096
+ */
1097
+ v1_translatable?: boolean;
1098
+ /**
1099
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1100
+ */
1101
+ since_version?: string;
1102
+ /**
1103
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1104
+ */
1105
+ migration_target_version?: string;
1106
+ /**
1107
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1108
+ */
1109
+ composition_model?: 'deterministic' | 'algorithmic';
1110
+ /**
1111
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1112
+ */
1113
+ provenance_required?: boolean;
1114
+ /**
1115
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1116
+ *
1117
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1118
+ */
1119
+ platform_extensions?: PlatformExtensionReference[];
1120
+ /**
1121
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1122
+ *
1123
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1124
+ */
1125
+ synthesis_nondeterministic?: boolean;
1126
+ /**
1127
+ * Default slots for display_tag canonical. Buyer ships a URL pointing at the third-party-served creative (JS, iframe, or 1×1 redirect) plus an optional backup image. Click and impression macros are substituted into the tag URL by the seller using `universal_macros`.
1128
+ */
1129
+ slots?: unknown;
1130
+ /**
1131
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1132
+ */
1133
+ production_window_business_days?: number;
1134
+ /**
1135
+ * Required tag rendering width in pixels — use for fixed-size slots. For multi-size flexible slots use `sizes[]`; for responsive use `min_width`/`max_width`/`min_height`/`max_height`. Exactly one of `(width, height)`, `sizes[]`, or `min/max_width` + `min/max_height` ranges MUST be set.
1136
+ * @minimum 1
1137
+ */
1138
+ width?: number;
1139
+ /**
1140
+ * Required tag rendering height in pixels. See `width` for size-mode mutual exclusion.
1141
+ * @minimum 1
1142
+ */
1143
+ height?: number;
1144
+ /**
1145
+ * List of accepted (width, height) pairs for a multi-size flexible slot. The buyer's third-party tag must render at one of the listed sizes; the seller picks which size to request at impression time. Mutually exclusive with `(width, height)` and with responsive ranges.
1146
+ */
1147
+ sizes?: {
1148
+ /**
1149
+ * @minimum 1
1150
+ */
1151
+ width: number;
1152
+ /**
1153
+ * @minimum 1
1154
+ */
1155
+ height: number;
1156
+ }[];
1157
+ /**
1158
+ * Minimum accepted width for responsive third-party tags. Pair with `max_width`. Mutually exclusive with `(width, height)` and `sizes[]`.
1159
+ * @minimum 1
1160
+ */
1161
+ min_width?: number;
1162
+ /**
1163
+ * Maximum accepted width for responsive third-party tags. Pair with `min_width`.
1164
+ * @minimum 1
1165
+ */
1166
+ max_width?: number;
1167
+ /**
1168
+ * Minimum accepted height for responsive third-party tags. Pair with `max_height`.
1169
+ * @minimum 1
1170
+ */
1171
+ min_height?: number;
1172
+ /**
1173
+ * Maximum accepted height for responsive third-party tags. Pair with `min_height`.
1174
+ * @minimum 1
1175
+ */
1176
+ max_height?: number;
1177
+ /**
1178
+ * Tag delivery mechanisms accepted.
1179
+ */
1180
+ supported_tag_types?: ('iframe' | 'javascript' | '1x1_redirect')[];
1181
+ /**
1182
+ * Whether the tag URL must be HTTPS.
1183
+ */
1184
+ ssl_required?: boolean;
1185
+ /**
1186
+ * Maximum redirect chain depth permitted.
1187
+ * @minimum 0
1188
+ */
1189
+ max_redirect_depth?: number;
1190
+ /**
1191
+ * Maximum tag-server response time in milliseconds.
1192
+ * @minimum 1
1193
+ */
1194
+ max_response_time_ms?: number;
1195
+ /**
1196
+ * Whether a backup image must accompany the tag for environments that cannot render the third-party tag.
1197
+ */
1198
+ backup_image_required?: boolean;
1199
+ /**
1200
+ * @minimum 1
1201
+ */
1202
+ backup_image_max_size_kb?: number;
1203
+ /**
1204
+ * Whether the buyer's tag must integrate IAB Open Measurement SDK for viewability.
1205
+ */
1206
+ om_sdk_required?: boolean;
1207
+ };
1208
+
1209
+ /**
1210
+ * Interactive HTML5 banner delivered as a zip archive. Slot: `html5_bundle` (zip asset). Tracking model: MRAID + IAB Open Measurement (OM-SDK) + click-tag macro substitution + backup image fallback. Receivers unpack the zip, validate internal structure, and serve from CDN. Distinct from `image` (static, non-interactive) and `display_tag` (third-party served). The zip's entry point is typically `index.html`; click handling uses `clickTag` (or `clickTAG`) macro substitution.
1211
+ */
1212
+ export type CanonicalFormatHTML5Banner = SizeModeMutex & {
1213
+ /**
1214
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
1215
+ *
1216
+ * Three drivers of `experimental: true`:
1217
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1218
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1219
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1220
+ *
1221
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1222
+ */
1223
+ experimental?: boolean;
1224
+ /**
1225
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1226
+ */
1227
+ deprecated?: boolean;
1228
+ /**
1229
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
1230
+ *
1231
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
1232
+ */
1233
+ v1_translatable?: boolean;
1234
+ /**
1235
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1236
+ */
1237
+ since_version?: string;
1238
+ /**
1239
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1240
+ */
1241
+ migration_target_version?: string;
1242
+ /**
1243
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1244
+ */
1245
+ composition_model?: 'deterministic' | 'algorithmic';
1246
+ /**
1247
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1248
+ */
1249
+ provenance_required?: boolean;
1250
+ /**
1251
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1252
+ *
1253
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1254
+ */
1255
+ platform_extensions?: PlatformExtensionReference[];
1256
+ /**
1257
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1258
+ *
1259
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1260
+ */
1261
+ synthesis_nondeterministic?: boolean;
1262
+ /**
1263
+ * Default slots for html5 canonical. Buyer ships a zip bundle plus optional backup image (required when `backup_image_required: true`) and clickthrough URL. The zip's entry point is typically `index.html`; click handling uses the `clickTag` (or `clickTAG`) macro substituted by the seller at serve time.
1264
+ */
1265
+ slots?: unknown;
1266
+ /**
1267
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1268
+ */
1269
+ production_window_business_days?: number;
1270
+ /**
1271
+ * Required banner width in pixels — use for fixed-size slots. For multi-size flexible slots use `sizes[]`; for responsive use `min_width`/`max_width`/`min_height`/`max_height`. Exactly one of `(width, height)`, `sizes[]`, or `min/max_width` + `min/max_height` ranges MUST be set.
1272
+ * @minimum 1
1273
+ */
1274
+ width?: number;
1275
+ /**
1276
+ * Required banner height in pixels. See `width` for size-mode mutual exclusion.
1277
+ * @minimum 1
1278
+ */
1279
+ height?: number;
1280
+ /**
1281
+ * List of accepted (width, height) pairs for a multi-size flexible slot (publisher banner that accepts 300×250 OR 728×90 OR 970×250). Mirrors OpenRTB `banner.format[]`. Mutually exclusive with `(width, height)` and with responsive ranges.
1282
+ */
1283
+ sizes?: {
1284
+ /**
1285
+ * @minimum 1
1286
+ */
1287
+ width: number;
1288
+ /**
1289
+ * @minimum 1
1290
+ */
1291
+ height: number;
1292
+ }[];
1293
+ /**
1294
+ * Minimum accepted width for responsive HTML5 banners that adapt within a range. Pair with `max_width`. Mutually exclusive with `(width, height)` and `sizes[]`.
1295
+ * @minimum 1
1296
+ */
1297
+ min_width?: number;
1298
+ /**
1299
+ * Maximum accepted width for responsive HTML5 banners. Pair with `min_width`.
1300
+ * @minimum 1
1301
+ */
1302
+ max_width?: number;
1303
+ /**
1304
+ * Minimum accepted height for responsive HTML5 banners. Pair with `max_height`.
1305
+ * @minimum 1
1306
+ */
1307
+ min_height?: number;
1308
+ /**
1309
+ * Maximum accepted height for responsive HTML5 banners. Pair with `min_height`.
1310
+ * @minimum 1
1311
+ */
1312
+ max_height?: number;
1313
+ /**
1314
+ * Maximum initial-load file size (zip + above-the-fold assets) in kilobytes. IAB display standards: 200 KB for fixed sizes, 100 KB for mobile.
1315
+ * @minimum 1
1316
+ */
1317
+ max_initial_load_kb?: number;
1318
+ /**
1319
+ * Maximum polite-load file size after host-initiated subload, in kilobytes. IAB display standards: 500 KB for fixed sizes.
1320
+ * @minimum 1
1321
+ */
1322
+ max_polite_load_kb?: number;
1323
+ /**
1324
+ * Whether the host page must initiate the polite-load phase. IAB-compliant banners require true.
1325
+ */
1326
+ host_initiated_subload?: boolean;
1327
+ /**
1328
+ * Maximum total animation duration in milliseconds. IAB standard: 30000 (30 seconds).
1329
+ * @minimum 0
1330
+ */
1331
+ max_animation_duration_ms?: number;
1332
+ /**
1333
+ * Maximum CPU load percentage during render.
1334
+ * @minimum 1
1335
+ * @maximum 100
1336
+ */
1337
+ max_cpu_load_percent?: number;
1338
+ /**
1339
+ * Whether MRAID compatibility is required (mobile in-app).
1340
+ */
1341
+ mraid_required?: boolean;
1342
+ /**
1343
+ * Required MRAID version when mraid_required is true.
1344
+ */
1345
+ mraid_version?: '2.0' | '3.0';
1346
+ /**
1347
+ * Whether IAB Open Measurement SDK integration is required.
1348
+ */
1349
+ om_sdk_required?: boolean;
1350
+ /**
1351
+ * Name of the click-tag macro the bundle must use.
1352
+ */
1353
+ clicktag_macro?: 'clickTag' | 'clickTAG';
1354
+ /**
1355
+ * Whether a backup image must accompany the zip for non-HTML5 environments.
1356
+ */
1357
+ backup_image_required?: boolean;
1358
+ /**
1359
+ * Maximum backup image file size in kilobytes.
1360
+ * @minimum 1
1361
+ */
1362
+ backup_image_max_size_kb?: number;
1363
+ ssl_required?: boolean;
1364
+ };
1365
+
1366
+ /**
1367
+ * Direct audio creative — buyer ships an `audio` asset (mp3/aac/wav) for asset-driven products, or ships a `script` / `creative_brief` text asset for products where the seller produces audio internally (podcast host-reads, TTS synthesis). Optional companion slots: `companion_image`, `brand_name`, `landing_page_url`. Tracking model: standard impression + completion + companion-image-click pixels via universal_macros. Distinct from `audio_daast` (DAAST tag, inherent DAAST event tracking). For host-reads and synthesized audio, the format declares `asset_source: 'publisher_host_recorded'` or `'agent_synthesized'` plus `buyer_asset_acceptance: 'rejected'`; the format's `slots` declaration enumerates which assets the buyer ships (e.g., `script` text asset for host-reads). The seller decides how to consume each asset (render verbatim vs produce audio from text) — there is no separate manifest 'inputs' map; everything the buyer ships goes in `assets`.
1368
+ */
1369
+ export interface CanonicalFormatHostedAudio {
1370
+ /**
1371
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
1372
+ *
1373
+ * Three drivers of `experimental: true`:
1374
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1375
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1376
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1377
+ *
1378
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1379
+ */
1380
+ experimental?: boolean;
1381
+ /**
1382
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1383
+ */
1384
+ deprecated?: boolean;
1385
+ /**
1386
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
1387
+ *
1388
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
1389
+ */
1390
+ v1_translatable?: boolean;
1391
+ /**
1392
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1393
+ */
1394
+ since_version?: string;
1395
+ /**
1396
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1397
+ */
1398
+ migration_target_version?: string;
1399
+ /**
1400
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1401
+ */
1402
+ composition_model?: 'deterministic' | 'algorithmic';
1403
+ /**
1404
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1405
+ */
1406
+ provenance_required?: boolean;
1407
+ /**
1408
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1409
+ *
1410
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1411
+ */
1412
+ platform_extensions?: PlatformExtensionReference[];
1413
+ /**
1414
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1415
+ *
1416
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1417
+ */
1418
+ synthesis_nondeterministic?: boolean;
1419
+ /**
1420
+ * Default slots for buyer-uploaded audio. Host-read products override with a `script` (asset_type: text) or `creative_brief` (asset_type: brief) slot in place of `audio_main`, plus `asset_source: 'publisher_host_recorded'` and `buyer_asset_acceptance: 'rejected'`. TTS-from-script products override similarly with `asset_source: 'seller_pre_rendered_from_brief'`.
1421
+ */
1422
+ slots?: unknown;
1423
+ /**
1424
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1425
+ */
1426
+ production_window_business_days?: number;
1427
+ /**
1428
+ * [min, max] duration in milliseconds. **Precedence**: `duration_ms_exact` takes precedence when both ship on the same product. SDKs SHOULD lint a warning when both fields ship.
1429
+ */
1430
+ duration_ms_range?: number[];
1431
+ /**
1432
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship.
1433
+ * @minimum 1
1434
+ */
1435
+ duration_ms_exact?: number;
1436
+ audio_codecs?: ('mp3' | 'aac' | 'wav' | 'opus' | 'flac')[];
1437
+ audio_sample_rates?: number[];
1438
+ audio_channels?: ('mono' | 'stereo')[];
1439
+ /**
1440
+ * @minimum 1
1441
+ */
1442
+ min_bitrate_kbps?: number;
1443
+ /**
1444
+ * @minimum 1
1445
+ */
1446
+ max_bitrate_kbps?: number;
1447
+ /**
1448
+ * Required integrated loudness in LUFS (typical: -16 for streaming/podcast, -23 for broadcast). Negative values.
1449
+ */
1450
+ loudness_lufs?: number;
1451
+ /**
1452
+ * Permitted deviation from loudness_lufs in dB.
1453
+ * @minimum 0
1454
+ */
1455
+ loudness_tolerance_db?: number;
1456
+ /**
1457
+ * Maximum true-peak level in dBFS (typical: -2).
1458
+ */
1459
+ true_peak_dbfs?: number;
1460
+ /**
1461
+ * Where the rendered audio bytes come from. Single shared enum across canonicals (see `image.json#asset_source` for the full semantics). `publisher_host_recorded`: the publisher's host records the audio (podcast host-read pattern); buyer must use the publisher's build_creative capability. This value is audio-specific.
1462
+ */
1463
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1464
+ /**
1465
+ * Whether the product accepts buyer-uploaded audio. When `rejected`, the buyer cannot ship an audio asset directly — they must use build_creative (or sync_creatives with brief inputs) so the seller produces the audio. Combined with `asset_source`, lets a product declare 'I produce audio from briefs and refuse buyer uploads' (asset_source=`seller_pre_rendered_from_brief`, buyer_asset_acceptance=`rejected`).
1466
+ */
1467
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
1468
+ companion_image_required?: boolean;
1469
+ companion_image_aspect_ratio?: string;
1470
+ /**
1471
+ * @minimum 1
1472
+ */
1473
+ companion_image_max_file_size_kb?: number;
1474
+ /**
1475
+ * @minimum 1
1476
+ */
1477
+ brand_name_max_chars?: number;
1478
+ }
1479
+
1480
+ /**
1481
+ * Direct video file (mp4/webm/mov) hosted by the buyer. Slot: `video_main` (video asset, file or hosted URL), optional `headline`, `brand_name`, `cta`, `companion_banner`, `landing_page_url`. Tracking model: IAB Open Measurement SDK + external impression/click/quartile pixels via universal_macros. Orientation is a parameter (vertical 9:16 / horizontal 16:9 / square 1:1); slot shape includes optional `brand_name` (typical for vertical short-form) and optional `companion_banner` (typical for horizontal instream). Distinct from `video_vast` (VAST tag, inherent VAST event tracking) — receivers fire impression and click pixels at delivery time.
1482
+ */
1483
+ export interface CanonicalFormatHostedVideo {
1484
+ /**
1485
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
1486
+ *
1487
+ * Three drivers of `experimental: true`:
1488
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1489
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1490
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1491
+ *
1492
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1493
+ */
1494
+ experimental?: boolean;
1495
+ /**
1496
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1497
+ */
1498
+ deprecated?: boolean;
1499
+ /**
1500
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
1501
+ *
1502
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
1503
+ */
1504
+ v1_translatable?: boolean;
1505
+ /**
1506
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1507
+ */
1508
+ since_version?: string;
1509
+ /**
1510
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1511
+ */
1512
+ migration_target_version?: string;
1513
+ /**
1514
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1515
+ */
1516
+ composition_model?: 'deterministic' | 'algorithmic';
1517
+ /**
1518
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1519
+ */
1520
+ provenance_required?: boolean;
1521
+ /**
1522
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1523
+ *
1524
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1525
+ */
1526
+ platform_extensions?: PlatformExtensionReference[];
1527
+ /**
1528
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1529
+ *
1530
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1531
+ */
1532
+ synthesis_nondeterministic?: boolean;
1533
+ /**
1534
+ * Default slots for video_hosted canonical. Buyer ships a video asset (file or hosted URL); optional headline, primary text (long-form caption), CTA (typically constrained via `cta_values`), brand_name (typical for vertical short-form), companion_banner (typical for horizontal instream), and clickthrough URL. Products MAY override or extend the default — e.g., remove `companion_banner` for short-form vertical, narrow `cta` to a value enum, mark `landing_page_url` as required.
1535
+ */
1536
+ slots?: unknown;
1537
+ /**
1538
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1539
+ */
1540
+ production_window_business_days?: number;
1541
+ /**
1542
+ * Video orientation. Vertical = 9:16 (Reels, Stories, Shorts). Horizontal = 16:9 (instream, CTV). Square = 1:1 (in-feed).
1543
+ */
1544
+ orientation?: 'vertical' | 'horizontal' | 'square';
1545
+ /**
1546
+ * Aspect ratio. Inferred from orientation if omitted.
1547
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
1548
+ */
1549
+ aspect_ratio?: string;
1550
+ /**
1551
+ * @minimum 1
1552
+ */
1553
+ min_width?: number;
1554
+ /**
1555
+ * @minimum 1
1556
+ */
1557
+ min_height?: number;
1558
+ /**
1559
+ * @minimum 1
1560
+ */
1561
+ max_width?: number;
1562
+ /**
1563
+ * @minimum 1
1564
+ */
1565
+ max_height?: number;
1566
+ /**
1567
+ * [min, max] duration in milliseconds. **Precedence**: when both `duration_ms_exact` and `duration_ms_range` ship on the same product, `duration_ms_exact` takes precedence — buyers MUST validate against the exact value and ignore the range. The range is treated as advisory metadata in that case (e.g., for UI display showing the broader product family). SDKs SHOULD lint a warning when both fields ship; producers SHOULD pick one.
1568
+ */
1569
+ duration_ms_range?: number[];
1570
+ /**
1571
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship (see `duration_ms_range` description).
1572
+ * @minimum 1
1573
+ */
1574
+ duration_ms_exact?: number;
1575
+ video_codecs?: ('h264' | 'h265' | 'vp8' | 'vp9' | 'av1' | 'prores')[];
1576
+ audio_codecs?: ('aac' | 'mp3' | 'opus' | 'pcm')[];
1577
+ containers?: ('mp4' | 'webm' | 'mov')[];
1578
+ /**
1579
+ * @minimum 1
1580
+ */
1581
+ min_bitrate_kbps?: number;
1582
+ /**
1583
+ * @minimum 1
1584
+ */
1585
+ max_bitrate_kbps?: number;
1586
+ /**
1587
+ * @minimum 1
1588
+ */
1589
+ max_file_size_mb?: number;
1590
+ frame_rates?: number[];
1591
+ captions?: 'required' | 'recommended' | 'not_required';
1592
+ om_sdk_required?: boolean;
1593
+ /**
1594
+ * @minimum 1
1595
+ */
1596
+ headline_max_chars?: number;
1597
+ /**
1598
+ * @minimum 1
1599
+ */
1600
+ primary_text_max_chars?: number;
1601
+ /**
1602
+ * @minimum 1
1603
+ */
1604
+ brand_name_max_chars?: number;
1605
+ cta_values?: string[];
1606
+ /**
1607
+ * Permitted companion banner widths (instream video).
1608
+ */
1609
+ companion_banner_widths?: number[];
1610
+ companion_banner_heights?: number[];
1611
+ /**
1612
+ * Where the rendered asset bytes come from. Single shared enum across canonicals. See `image.json#asset_source` for the full semantics. `publisher_host_recorded` is audio-specific and has no defined behavior on video — adopters MUST select a value appropriate to the canonical.
1613
+ */
1614
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1615
+ /**
1616
+ * Whether the product accepts buyer-uploaded video. When `rejected`, the buyer cannot ship a video asset directly — they must use build_creative (or sync_creatives with brief inputs) so the seller produces the video.
1617
+ */
1618
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
1619
+ }
1620
+
1621
+ /**
1622
+ * Static image creative format. Slots: `image_main` (image asset, file or hosted URL), optional `headline` (text), `body_text` (text), `cta` (text/enum), `landing_page_url` (url). Tracking model: impression pixel + click URL via universal_macros, with optional viewability pixel. Distinct from `html5` (interactive bundles) and `display_tag` (third-party served). AR/dimensions narrow to specific sizes via product parameters — covers IAB display sizes (300x250, 728x90, 970x250, etc.) without a separate iab_size enum.
1623
+ */
1624
+ export type CanonicalFormatImage = SizeModeMutex & {
1625
+ /**
1626
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
1627
+ *
1628
+ * Three drivers of `experimental: true`:
1629
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1630
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1631
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1632
+ *
1633
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1634
+ */
1635
+ experimental?: boolean;
1636
+ /**
1637
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1638
+ */
1639
+ deprecated?: boolean;
1640
+ /**
1641
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
1642
+ *
1643
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
1644
+ */
1645
+ v1_translatable?: boolean;
1646
+ /**
1647
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1648
+ */
1649
+ since_version?: string;
1650
+ /**
1651
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1652
+ */
1653
+ migration_target_version?: string;
1654
+ /**
1655
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1656
+ */
1657
+ composition_model?: 'deterministic' | 'algorithmic';
1658
+ /**
1659
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1660
+ */
1661
+ provenance_required?: boolean;
1662
+ /**
1663
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1664
+ *
1665
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1666
+ */
1667
+ platform_extensions?: PlatformExtensionReference[];
1668
+ /**
1669
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1670
+ *
1671
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1672
+ */
1673
+ synthesis_nondeterministic?: boolean;
1674
+ /**
1675
+ * Default slots for image canonical. Buyer ships an image asset (file or hosted URL) plus optional headline, body text, primary text (long-form caption), CTA (typically constrained to an enum via `cta_values`), and clickthrough URL. Products MAY override the default — make `headline` required, narrow `cta` to a value enum, or remove slots the surface doesn't consume.
1676
+ */
1677
+ slots?: unknown;
1678
+ /**
1679
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1680
+ */
1681
+ production_window_business_days?: number;
1682
+ /**
1683
+ * Required image width in pixels — use for fixed-size slots (e.g., a 300×250 IAB MREC). For multi-size flexible slots (publisher MREC slot that accepts 300×250 OR 728×90 OR 970×250), use `sizes[]` instead; for responsive slots that adapt to viewport, use `min_width`/`max_width`/`min_height`/`max_height`. The three modes are mutually exclusive — set exactly one of `(width+height)`, `sizes[]`, or `min/max_width` + `min/max_height` ranges.
1684
+ * @minimum 1
1685
+ */
1686
+ width?: number;
1687
+ /**
1688
+ * Required image height in pixels. See `width` for size-mode mutual exclusion.
1689
+ * @minimum 1
1690
+ */
1691
+ height?: number;
1692
+ /**
1693
+ * List of accepted (width, height) pairs for a multi-size flexible slot. Buyer ships an asset matching one of the listed sizes; SDK validates `assets.image_main.{width,height}` against the list (any-match). Mirrors OpenRTB `banner.format[]` semantics — one declaration with N accepted sizes is cleaner than N format_options entries. Mutually exclusive with `(width, height)` and with `min/max_width` + `min/max_height` ranges.
1694
+ */
1695
+ sizes?: {
1696
+ /**
1697
+ * @minimum 1
1698
+ */
1699
+ width: number;
1700
+ /**
1701
+ * @minimum 1
1702
+ */
1703
+ height: number;
1704
+ }[];
1705
+ /**
1706
+ * Minimum accepted width in pixels for responsive slots that adapt within a range (e.g., 'any width from 300 to 970'). Use with `max_width` (and optionally `min_height`/`max_height`). Mutually exclusive with `(width, height)` and `sizes[]`.
1707
+ * @minimum 1
1708
+ */
1709
+ min_width?: number;
1710
+ /**
1711
+ * Maximum accepted width in pixels for responsive slots. Pair with `min_width`. See `min_width` for size-mode mutual exclusion.
1712
+ * @minimum 1
1713
+ */
1714
+ max_width?: number;
1715
+ /**
1716
+ * Minimum accepted height in pixels for responsive slots. Pair with `max_height`.
1717
+ * @minimum 1
1718
+ */
1719
+ min_height?: number;
1720
+ /**
1721
+ * Maximum accepted height in pixels for responsive slots. Pair with `min_height`.
1722
+ * @minimum 1
1723
+ */
1724
+ max_height?: number;
1725
+ /**
1726
+ * Optional aspect ratio constraint (e.g., '1.91:1', '1:1'). When provided alongside `width`/`height`, must agree. When used with `sizes[]` or responsive ranges, narrows accepted entries to those matching the aspect ratio.
1727
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
1728
+ */
1729
+ aspect_ratio?: string;
1730
+ /**
1731
+ * Maximum file size in kilobytes.
1732
+ * @minimum 1
1733
+ */
1734
+ max_file_size_kb?: number;
1735
+ /**
1736
+ * Permitted image file formats.
1737
+ */
1738
+ image_formats?: ('jpg' | 'jpeg' | 'png' | 'gif' | 'webp' | 'svg')[];
1739
+ /**
1740
+ * Whether the image and its trackers must be served over HTTPS.
1741
+ */
1742
+ ssl_required?: boolean;
1743
+ /**
1744
+ * @minimum 1
1745
+ */
1746
+ headline_max_chars?: number;
1747
+ /**
1748
+ * @minimum 1
1749
+ */
1750
+ body_text_max_chars?: number;
1751
+ /**
1752
+ * Permitted CTA values for this product (e.g., ['LEARN_MORE', 'SHOP_NOW']).
1753
+ */
1754
+ cta_values?: string[];
1755
+ /**
1756
+ * Where the rendered asset bytes come from. Single shared enum across all canonicals (`image`, `video_hosted`, `audio_hosted` — replaces the earlier per-canonical `image_source` / `video_source` / `audio_source` fields). `buyer_uploaded` (default): buyer ships a pre-rendered asset. `publisher_host_recorded`: publisher's host records the asset (audio-specific; podcast host-read pattern). `seller_pre_rendered_from_brief`: buyer ships a brief plus structured copy; seller renders ONE asset at sync_creatives or build_creative time (generative-DSP pattern). `seller_human_designed`: seller's design team renders manually from a brief. `agent_synthesized`: AI synthesis pipeline; pair with `synthesis_nondeterministic: true` when the platform cannot guarantee in-spec output (Veo/Sora/Imagen-class).
1757
+ *
1758
+ * Not every value is meaningful on every canonical — `publisher_host_recorded` is audio-specific; on `image` or `video_hosted` it has no defined behavior. Adopters MUST select a value appropriate to the canonical's asset type. The `slots` declaration is the binding contract for what the buyer ships; `asset_source` is informational and lets buyers understand the production model when picking products.
1759
+ */
1760
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1761
+ /**
1762
+ * Whether the product accepts buyer-uploaded assets. When `rejected`, the buyer cannot ship pre-rendered bytes directly — they must use build_creative (or sync_creatives with brief inputs) so the seller produces the asset. Combined with `asset_source`, lets a product declare 'I produce assets from briefs and refuse buyer uploads' (asset_source=`seller_pre_rendered_from_brief`, buyer_asset_acceptance=`rejected`).
1763
+ */
1764
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
1765
+ };
1766
+
1767
+ /**
1768
+ * Multi-card swipeable carousel. The buyer ships a `cards` slot whose value is an **array** of [card-asset](/schemas/core/assets/card-asset.json) objects (a single key with an array value — NOT one key per card, NOT dotted/bracketed paths). Each card-asset carries: `asset_type: "card"`, `media` (an image or video asset), optional `headline` (text), optional `landing_page_url` (url asset). Per-card structure is the same across all cards; mixed orientations not allowed within a single carousel. Tracking model: per-card impression and engagement pixels + carousel-level engagement (swipe, view-time). Allowed asset types for a card's `media` field: `image` and `video` (Meta-style mixed-media); platforms can narrow to image-only or video-only via `allowed_card_media_asset_types`.
1769
+ *
1770
+ * The manifest's `assets.cards` value is an array of card-asset objects. Example: `"cards": [{"asset_type": "card", "media": {"asset_type": "image", "url": "..."}, "headline": "Buy now", "landing_page_url": {"asset_type": "url", "url_type": "clickthrough", "url": "..."}}, ...]`. Each card-asset validates against the card schema; per-card platform extensions attach via the card's `platform_extensions` field, never via inline non-canonical keys.
1771
+ */
1772
+ export interface CanonicalFormatImageCarousel {
1773
+ /**
1774
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
1775
+ *
1776
+ * Three drivers of `experimental: true`:
1777
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
1778
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1779
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1780
+ *
1781
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
1782
+ */
1783
+ experimental?: boolean;
1784
+ /**
1785
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1786
+ */
1787
+ deprecated?: boolean;
1788
+ /**
1789
+ * Inherently new in v2 — multi-card carousels (Meta carousel, Pinterest pin collections, Snap collection ads) weren't expressible as v1 named formats. SDKs MUST NOT emit `FORMAT_PROJECTION_FAILED` for products using this canonical; the v1-unreachability is structural.
1790
+ */
1791
+ v1_translatable?: unknown;
1792
+ /**
1793
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1794
+ */
1795
+ since_version?: string;
1796
+ /**
1797
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1798
+ */
1799
+ migration_target_version?: string;
1800
+ /**
1801
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1802
+ */
1803
+ composition_model?: 'deterministic' | 'algorithmic';
1804
+ /**
1805
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1806
+ */
1807
+ provenance_required?: boolean;
1808
+ /**
1809
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1810
+ *
1811
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1812
+ */
1813
+ platform_extensions?: PlatformExtensionReference[];
1814
+ /**
1815
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1816
+ *
1817
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1818
+ */
1819
+ synthesis_nondeterministic?: boolean;
1820
+ /**
1821
+ * Default slots for image_carousel. The `cards` slot's value in the manifest is an array of [card-asset](/schemas/core/assets/card-asset.json) objects; `min` / `max` constrain card count.
1822
+ */
1823
+ slots?: unknown;
1824
+ /**
1825
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1826
+ */
1827
+ production_window_business_days?: number;
1828
+ /**
1829
+ * Aspect ratio shared across all cards (e.g., '1:1', '1.91:1', '4:5').
1830
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
1831
+ */
1832
+ card_aspect_ratio?: string;
1833
+ /**
1834
+ * Minimum card count (typical: 2 or 3).
1835
+ * @minimum 2
1836
+ */
1837
+ min_cards?: number;
1838
+ /**
1839
+ * Maximum card count (typical: 6, 10, or 35 depending on platform).
1840
+ */
1841
+ max_cards?: number;
1842
+ /**
1843
+ * Asset types each card's `media` field may carry. Default: ['image']. Polymorphic carousels (Meta) allow ['image', 'video']. Renamed from `allowed_card_asset_types` to disambiguate that this constrains the card's media payload, not the card-asset itself (which is always asset_type: "card").
1844
+ */
1845
+ allowed_card_media_asset_types?: ('image' | 'video')[];
1846
+ /**
1847
+ * DEPRECATED — alias for `allowed_card_media_asset_types`. Kept for back-compat; prefer the new field name. Removed in 5.0.
1848
+ */
1849
+ allowed_card_asset_types?: ('image' | 'video')[];
1850
+ /**
1851
+ * @minimum 1
1852
+ */
1853
+ card_image_max_file_size_kb?: number;
1854
+ /**
1855
+ * @minimum 1
1856
+ */
1857
+ card_video_max_duration_ms?: number;
1858
+ /**
1859
+ * Maximum length of the carousel-level primary text.
1860
+ * @minimum 1
1861
+ */
1862
+ primary_text_max_chars?: number;
1863
+ /**
1864
+ * Per-card headline character limit. Governs the `headline` field on each card-asset in the `cards` slot.
1865
+ * @minimum 1
1866
+ */
1867
+ card_headline_max_chars?: number;
1868
+ /**
1869
+ * Per-card description character limit. Governs the `description` field on each card-asset in the `cards` slot. Distinct from `card_headline_max_chars`: description is longer body copy (typically 100-500 chars); headline is the short label (typically 25-40 chars).
1870
+ * @minimum 1
1871
+ */
1872
+ card_description_max_chars?: number;
1873
+ ssl_required?: boolean;
1874
+ }
1875
+
1876
+ /**
1877
+ * IAB-shaped native creative for in-feed and content-recommendation surfaces. Default slots cover the primary IAB OpenRTB Native 1.2 asset types — `title` (Title Asset), `body_text` (Data Asset type 2), `main_image` (Image Asset main), `icon` (Image Asset icon), `cta` (Data Asset type 12), `advertiser_name` (Data Asset type 1), `sponsored_label` (Title-adjacent), `landing_page_url` (Link Asset), `display_url` (Data Asset type 11 — visible URL/domain, distinct from clickthrough), `rating` (Data Asset type 3 — app/product rating), `price` (Data Asset type 6 — product price), plus renderer-fired `impression_tracker` / `viewability_tracker` / `click_tracker` (`pixel_tracker`). Products MAY use `slots_override` to add other IAB Native data asset types (likes — type 4, downloads — type 5, saleprice — type 7, phone_number — type 8, address — type 9, desc2 — type 10, etc.) or to remove slots the surface doesn't render. The publisher's renderer assembles these into its own look-and-feel — feed card, content-recommendation slot, in-stream native unit. Buyer ships a single asset bundle; the surface chooses presentation.
1878
+ *
1879
+ * **Scope (normative — buyer-agent routing).** This canonical is the home for:
1880
+ * - IAB OpenRTB Native 1.2 in-feed native ads (publisher feeds, app feeds)
1881
+ * - Content-recommendation widgets (Taboola, Outbrain, Yahoo Recommendations)
1882
+ * - AdMob Native / Yahoo Native publisher slots
1883
+ * - In-feed sponsored placements without catalog dependency
1884
+ *
1885
+ * **Not this canonical:**
1886
+ * - Catalog-driven retail-media (Amazon SP, Criteo SP, CitrusAd SP) — use `sponsored_placement` (requires `source_catalog`).
1887
+ * - Algorithmic surface that picks from a buyer-supplied asset pool (Google PMax, Meta Advantage+) — use `responsive_creative`.
1888
+ * - Multi-card carousel — use `image_carousel`.
1889
+ * - Video-first native units where the asset is a hosted video file — use `video_hosted` with `applies_to_channels: ["native"]`.
1890
+ *
1891
+ * Distinct from `sponsored_placement` along the catalog axis: native_in_feed is asset-bundle composition; sponsored_placement is catalog-row composition. A buyer agent reading `format_kind: native_in_feed` knows to assemble title + image + body + CTA; reading `format_kind: sponsored_placement` knows to attach a catalog feed.
1892
+ */
1893
+ export interface CanonicalFormatNativeInFeed {
1894
+ /**
1895
+ * Stable at 3.1 GA. Shape mirrors IAB OpenRTB Native 1.2 — the renderer contract is well-established across in-feed native and content-recommendation adopters.
1896
+ */
1897
+ experimental?: unknown;
1898
+ /**
1899
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
1900
+ */
1901
+ deprecated?: boolean;
1902
+ /**
1903
+ * Translates to v1 named native formats (e.g., `native_standard`, `native_content`) via the projection registry. Sellers with existing v1 named native formats SHOULD point `v1_format_ref[]` at them.
1904
+ */
1905
+ v1_translatable?: unknown;
1906
+ /**
1907
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
1908
+ */
1909
+ since_version?: string;
1910
+ /**
1911
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
1912
+ */
1913
+ migration_target_version?: string;
1914
+ /**
1915
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
1916
+ */
1917
+ composition_model?: 'deterministic' | 'algorithmic';
1918
+ /**
1919
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
1920
+ */
1921
+ provenance_required?: boolean;
1922
+ /**
1923
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
1924
+ *
1925
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
1926
+ */
1927
+ platform_extensions?: PlatformExtensionReference[];
1928
+ /**
1929
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
1930
+ *
1931
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
1932
+ */
1933
+ synthesis_nondeterministic?: boolean;
1934
+ /**
1935
+ * Default slot shape for native_in_feed. Mirrors IAB OpenRTB Native 1.2 asset types. Products MAY override (`slots_override` on the projection ref) to narrow per-slot limits (`max_chars` on title/body) or remove unused slots (a content-recommendation slot that doesn't display an icon).
1936
+ */
1937
+ slots?: unknown;
1938
+ /**
1939
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
1940
+ */
1941
+ production_window_business_days?: number;
1942
+ /**
1943
+ * Maximum character length for the title slot. IAB native typical: 25 (short) to 90 (long). Buyer agents SHOULD validate ship-time title length against this.
1944
+ * @minimum 1
1945
+ */
1946
+ title_max_chars?: number;
1947
+ /**
1948
+ * Maximum character length for the body_text slot. IAB native typical: 90 (mainline) to 140 (extended).
1949
+ * @minimum 1
1950
+ */
1951
+ body_text_max_chars?: number;
1952
+ /**
1953
+ * Maximum character length for the cta slot. Typical: 15–25.
1954
+ * @minimum 1
1955
+ */
1956
+ cta_max_chars?: number;
1957
+ /**
1958
+ * Permitted CTA values for this product (e.g., ['LEARN_MORE', 'SHOP_NOW', 'SIGN_UP', 'DOWNLOAD']). When set, narrows the cta slot to a closed enum.
1959
+ */
1960
+ cta_values?: string[];
1961
+ /**
1962
+ * Accepted (width, height) pairs for the main_image slot. Common IAB native sizes: 1200×627 (1.91:1), 1080×1080 (1:1), 1080×1350 (4:5).
1963
+ */
1964
+ main_image_sizes?: {
1965
+ /**
1966
+ * @minimum 1
1967
+ */
1968
+ width: number;
1969
+ /**
1970
+ * @minimum 1
1971
+ */
1972
+ height: number;
1973
+ }[];
1974
+ /**
1975
+ * Required (width, height) for the icon slot when present (typical: 80×80 or 100×100).
1976
+ */
1977
+ icon_size?: {
1978
+ /**
1979
+ * @minimum 1
1980
+ */
1981
+ width: number;
1982
+ /**
1983
+ * @minimum 1
1984
+ */
1985
+ height: number;
1986
+ };
1987
+ /**
1988
+ * Maximum file size in kilobytes for main_image and icon.
1989
+ * @minimum 1
1990
+ */
1991
+ max_image_file_size_kb?: number;
1992
+ /**
1993
+ * Permitted image file formats.
1994
+ */
1995
+ image_formats?: ('jpg' | 'jpeg' | 'png' | 'gif' | 'webp')[];
1996
+ /**
1997
+ * Whether trackers, landing pages, and image URLs must be served over HTTPS.
1998
+ */
1999
+ ssl_required?: boolean;
2000
+ /**
2001
+ * Where the rendered native assets come from. `publisher_host_recorded` is omitted (audio-specific and not meaningful for native). Other values mirror the shared production-source axis used on `image` / `video_hosted`. `buyer_uploaded` (default): buyer ships pre-rendered title/image/body. `seller_pre_rendered_from_brief`: buyer ships a brief, seller renders the native bundle. `agent_synthesized`: AI synthesis pipeline produces title + image + body from a brief; pair with `synthesis_nondeterministic: true` for generative pipelines that can't guarantee in-spec output.
2002
+ */
2003
+ asset_source?: 'buyer_uploaded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
2004
+ /**
2005
+ * Whether the product accepts buyer-uploaded native assets. When `rejected`, the buyer cannot ship pre-rendered title/image/body — they must use `build_creative` (or `sync_creatives` with brief inputs) so the seller produces the native bundle from a brief.
2006
+ */
2007
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
2008
+ }
2009
+
2010
+ /**
2011
+ * Buyer supplies a pool of typed assets (multiple headlines, descriptions, images, videos, logos); the surface algorithmically composes combinations per placement. **Composition is algorithmic** — surface picks combinations and reports per-asset performance breakdowns. Covers Google Responsive Display Ads (RDA), Responsive Search Ads (RSA), Performance Max (PMax), Demand Gen, and Meta Advantage+ creative. Industry term: "Responsive" (Google) / "Advantage+ creative" (Meta) / "Dynamic Creative" (older Meta term). Distinct from `sponsored_placement` (catalog-driven, deterministic) and `agent_placement` (AI-surface composition). The structured `slots` field below enumerates expected canonical asset_group_id slots; per-slot count/length narrowing lives in flat parameters (`headlines_min`, `headline_max_chars`, etc.).
2012
+ */
2013
+ export interface CanonicalFormatResponsiveCreative {
2014
+ /**
2015
+ * Marked experimental at 3.1 GA: composition is algorithmic (the surface picks combinations and reports per-asset breakdowns), and there's no clean v1-translatable equivalent. Buyers ship asset pools rather than rendered creatives; the surface's per-impression composition cannot be predicted by `validate_input`. Adopters SHOULD validate behavior per surface (Google PMax vs Meta Advantage+ creative differ meaningfully).
2016
+ */
2017
+ experimental?: unknown;
2018
+ /**
2019
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
2020
+ */
2021
+ deprecated?: boolean;
2022
+ /**
2023
+ * Inherently new in v2 — algorithmic asset-pool composition (Google PMax / Meta Advantage+ creative) wasn't expressible as v1 named formats. SDKs MUST NOT emit `FORMAT_PROJECTION_FAILED` for products using this canonical; the v1-unreachability is structural.
2024
+ */
2025
+ v1_translatable?: unknown;
2026
+ /**
2027
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
2028
+ */
2029
+ since_version?: string;
2030
+ /**
2031
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
2032
+ */
2033
+ migration_target_version?: string;
2034
+ /**
2035
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
2036
+ */
2037
+ composition_model?: 'deterministic' | 'algorithmic';
2038
+ /**
2039
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
2040
+ */
2041
+ provenance_required?: boolean;
2042
+ /**
2043
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
2044
+ *
2045
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
2046
+ */
2047
+ platform_extensions?: PlatformExtensionReference[];
2048
+ /**
2049
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
2050
+ *
2051
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
2052
+ */
2053
+ synthesis_nondeterministic?: boolean;
2054
+ slots?: unknown;
2055
+ /**
2056
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
2057
+ */
2058
+ production_window_business_days?: number;
2059
+ /**
2060
+ * @minimum 0
2061
+ */
2062
+ headlines_min?: number;
2063
+ /**
2064
+ * @minimum 0
2065
+ */
2066
+ headlines_max?: number;
2067
+ /**
2068
+ * @minimum 1
2069
+ */
2070
+ headline_max_chars?: number;
2071
+ /**
2072
+ * @minimum 0
2073
+ */
2074
+ long_headlines_min?: number;
2075
+ /**
2076
+ * @minimum 0
2077
+ */
2078
+ long_headlines_max?: number;
2079
+ /**
2080
+ * @minimum 1
2081
+ */
2082
+ long_headline_max_chars?: number;
2083
+ /**
2084
+ * @minimum 0
2085
+ */
2086
+ descriptions_min?: number;
2087
+ /**
2088
+ * @minimum 0
2089
+ */
2090
+ descriptions_max?: number;
2091
+ /**
2092
+ * @minimum 1
2093
+ */
2094
+ description_max_chars?: number;
2095
+ /**
2096
+ * @minimum 0
2097
+ */
2098
+ images_landscape_min?: number;
2099
+ /**
2100
+ * @minimum 0
2101
+ */
2102
+ images_landscape_max?: number;
2103
+ images_landscape_aspect_ratio?: string;
2104
+ /**
2105
+ * @minimum 0
2106
+ */
2107
+ images_square_min?: number;
2108
+ /**
2109
+ * @minimum 0
2110
+ */
2111
+ images_square_max?: number;
2112
+ /**
2113
+ * @minimum 0
2114
+ */
2115
+ images_vertical_min?: number;
2116
+ /**
2117
+ * @minimum 0
2118
+ */
2119
+ images_vertical_max?: number;
2120
+ /**
2121
+ * @minimum 0
2122
+ */
2123
+ videos_min?: number;
2124
+ /**
2125
+ * @minimum 0
2126
+ */
2127
+ videos_max?: number;
2128
+ /**
2129
+ * @minimum 1
2130
+ */
2131
+ video_min_duration_ms?: number;
2132
+ /**
2133
+ * @minimum 1
2134
+ */
2135
+ video_max_duration_ms?: number;
2136
+ /**
2137
+ * @minimum 0
2138
+ */
2139
+ logo_min?: number;
2140
+ /**
2141
+ * @minimum 0
2142
+ */
2143
+ logo_max?: number;
2144
+ logo_aspect_ratios?: string[];
2145
+ /**
2146
+ * @minimum 1
2147
+ */
2148
+ business_name_max_chars?: number;
2149
+ /**
2150
+ * @minimum 1
2151
+ */
2152
+ asset_image_max_file_size_kb?: number;
2153
+ /**
2154
+ * Whether the product can additionally consume a catalog reference (e.g., PMax with product feed).
2155
+ */
2156
+ supports_catalog_input?: boolean;
2157
+ }
2158
+
2159
+ /**
2160
+ * Catalog-driven retail-media format. Slot: `source_catalog` (catalog asset — product/SKU/ASIN/GTIN catalog reference, REQUIRED), optional `hero_asset`, optional `landing_page_url`. Buyer supplies the catalog reference; surface composes per-item or multi-item rendering using its native placement template. **Composition is deterministic** — buyer can predict per-slot rendering from the catalog item structure. Tracking model: per-item impression + click + conversion (catalog-keyed via offering_id/sku/gtin macros). Covers Amazon Sponsored Products, Criteo Sponsored Products, CitrusAd Sponsored Products, Walmart Connect Sponsored Products, Pinterest Collection (catalog-driven mode).
2161
+ *
2162
+ * **Scope (normative — buyer-agent routing).** This canonical is the home for catalog-driven retail-media placements ONLY. The defining feature is the `source_catalog` slot — products under this canonical compose their creative *per catalog item* using the buyer-supplied catalog feed. Without a catalog feed there is nothing to render against. Buyer agents reading `format_kind: sponsored_placement` MUST attach a catalog reference; sellers MUST require `source_catalog` in the manifest.
2163
+ *
2164
+ * **Not this canonical (route elsewhere):**
2165
+ * - IAB in-feed native ads, content-recommendation widgets (Taboola, Outbrain, Yahoo Native, AdMob Native, in-feed sponsored cards) — use `native_in_feed` (asset-bundle composition; no catalog).
2166
+ * - Algorithmic surface that picks from a buyer-supplied asset pool (Google PMax, Meta Advantage+) — use `responsive_creative`.
2167
+ * - Single-image or single-video creative — use `image` or `video_hosted`.
2168
+ *
2169
+ * The earlier broader framing ('any sponsored placement') was too loose for buyer-agent routing — a buyer reading `sponsored_placement` couldn't disambiguate a catalog-driven Amazon SP from an in-feed Taboola widget. As of 3.1, the canonical is narrowed to catalog-keyed retail-media; native moves to `native_in_feed`. Distinct from `responsive_creative` (algorithmic combinator from buyer pool) and `agent_placement` (text/audio AI-surface composition).
2170
+ */
2171
+ export interface CanonicalFormatSponsoredPlacementRetailMediaCatalogDriven {
2172
+ /**
2173
+ * Marked experimental at 3.1 GA: the canonical covers 4 meaningfully different retail-media adapter contracts (Amazon SP, Criteo SP / CitrusAd SP, Pinterest Collection, generative-per-SKU). Adopter contracts vary; buyers MUST validate per-adapter behavior before routing budget. Promotion to non-experimental gated on the #4592 adapter-contract docs work.
2174
+ */
2175
+ experimental?: unknown;
2176
+ /**
2177
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
2178
+ */
2179
+ deprecated?: boolean;
2180
+ /**
2181
+ * Inherently new in v2 — retail-media catalog placements weren't expressible as v1 named formats. SDKs MUST NOT emit `FORMAT_PROJECTION_FAILED` for products using this canonical; the v1-unreachability is structural, not a registry-coverage gap.
2182
+ */
2183
+ v1_translatable?: unknown;
2184
+ /**
2185
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
2186
+ */
2187
+ since_version?: string;
2188
+ /**
2189
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
2190
+ */
2191
+ migration_target_version?: string;
2192
+ /**
2193
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
2194
+ */
2195
+ composition_model?: 'deterministic' | 'algorithmic';
2196
+ /**
2197
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
2198
+ */
2199
+ provenance_required?: boolean;
2200
+ /**
2201
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
2202
+ *
2203
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
2204
+ */
2205
+ platform_extensions?: PlatformExtensionReference[];
2206
+ /**
2207
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
2208
+ *
2209
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
2210
+ */
2211
+ synthesis_nondeterministic?: boolean;
2212
+ slots?: unknown;
2213
+ /**
2214
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
2215
+ */
2216
+ production_window_business_days?: number;
2217
+ /**
2218
+ * Catalog types this product accepts.
2219
+ */
2220
+ supported_catalog_types?: ('product' | 'store' | 'offering' | 'hotel' | 'flight' | 'vehicle' | 'real_estate' | 'education' | 'destination' | 'app' | 'job' | 'inventory')[];
2221
+ /**
2222
+ * Minimum catalog item count buyer must supply.
2223
+ * @minimum 1
2224
+ */
2225
+ min_items?: number;
2226
+ /**
2227
+ * Maximum items considered for placement.
2228
+ */
2229
+ max_items?: number;
2230
+ /**
2231
+ * How items map to delivery: per_item = one ad per catalog item; multi_item_in_creative = composed multi-item ad (Pinterest Collection, Snap Collection); single_item = one ad showing one item.
2232
+ */
2233
+ fanout_mode?: 'per_item' | 'multi_item_in_creative' | 'single_item';
2234
+ /**
2235
+ * Catalog item fields the seller requires (e.g., ['title', 'image_url', 'price']).
2236
+ */
2237
+ required_catalog_fields?: string[];
2238
+ /**
2239
+ * Catalog identifier types the placement renders against.
2240
+ */
2241
+ supported_id_types?: ('asin' | 'sku' | 'gtin' | 'offering_id' | 'store_id' | 'hotel_id' | 'flight_id' | 'vehicle_id' | 'listing_id' | 'program_id' | 'destination_id' | 'app_id' | 'job_id')[];
2242
+ /**
2243
+ * Whether the buyer can supply a hero/banner asset alongside the catalog (Pinterest Collection pattern).
2244
+ */
2245
+ hero_asset_supported?: boolean;
2246
+ /**
2247
+ * How each per-item creative is produced. Covers the same production-source axis as `asset_source` on `image` / `video_hosted` / `audio_hosted` but with a 4-value subset — drops `publisher_host_recorded` because it's audio-specific and doesn't apply to retail-media catalog placements. SDK codegen MAY share a base enum and narrow per-canonical, or emit two distinct enums; either way the wire values overlap exactly for the 4 retained values. `buyer_uploaded` (default, current Amazon/Criteo/CitrusAd pattern): the buyer's catalog already contains rendered assets per item; the seller composes the placement using those assets. ("Uploaded" reads slightly off for catalog-keyed items where the buyer didn't actively upload bytes — the catalog ingestion already supplied them — but the semantic is the same: rendered bytes are buyer-supplied, not seller-produced.) `seller_pre_rendered_from_brief`: the buyer ships a brief plus the catalog reference; the seller renders one creative per catalog item from the brief at sync_creatives time. `seller_human_designed`: seller's design team produces per-item renders manually. `agent_synthesized`: AI synthesis pipeline produces per-item renders; pair with `synthesis_nondeterministic: true` for Veo/Sora-class generative video applied per item. Captures the multi-output generative pattern (1 brief × N catalog items → N rendered creatives) under the existing canonical without requiring a separate canonical. Distinct from `fanout_mode`, which describes how items map to delivery slots after rendering.
2248
+ */
2249
+ item_production_model?: 'buyer_uploaded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
2250
+ }
2251
+
2252
+ /**
2253
+ * VAST-tag-delivered video creative. Slot: `vast_tag` (vast asset, URL or inline XML, VAST 2.x-4.x). Tracking model: VAST events inherent to the spec — `impression`, `firstQuartile`, `midpoint`, `thirdQuartile`, `complete`, `start`, `pause`, `resume`, `mute`, `unmute`, `expand`, `collapse`, `fullscreen`, `creativeView`, `clickTracking`, `error`. VPAID interactivity via `vpaid_enabled: true` flag. SIMID extensions for interactive video supported as VAST extensions. Orientation is a parameter (vertical / horizontal / square). Distinct from `video_hosted` (direct file with external tracking).
2254
+ */
2255
+ export interface CanonicalFormatVASTVideo {
2256
+ /**
2257
+ * When true, this canonical (or a seller's specific narrowing of it) may not work as declared — adopters SHOULD have a v1 fallback ready and SHOULD NOT route production budget without testing. Same semantics as `experimental` on protocols: 'this is shipping but may break, evolve, or fail.' Buyers reading `experimental: true` SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via the v2 declaration's `v1_format_ref`).
2258
+ *
2259
+ * Three drivers of `experimental: true`:
2260
+ * 1. **Spec maturity** — the canonical's tracking model or parameter shape is still being settled (`agent_placement`'s tracking macros, `sponsored_placement`'s per-adapter contracts, `responsive_creative`'s algorithmic composition).
2261
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
2262
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
2263
+ *
2264
+ * Replaces the earlier `status` enum (`stable | preview | deprecated`) + `runtime_status` enum (`stable | preview | declared_only`) — two axes with subtle overlap. The single boolean is what buyers actually care about: do I treat this as production-stable or as 'try at my own risk.' Sellers SHOULD set `experimental: true` on canonicals or product declarations that aren't yet production-ready, regardless of which axis (spec, runtime, custom) drives the experimentation. The 6 IAB/VAST/DAAST re-encodings (`image`, `display_tag`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`) default to non-experimental at the canonical level; sellers MAY still mark a specific product declaration experimental (e.g., a beta runtime path for an existing product).
2265
+ */
2266
+ experimental?: boolean;
2267
+ /**
2268
+ * When true, this canonical (or a seller's specific narrowing of it) is going away. Existing adopters are supported through the deprecation cycle; new adoption is discouraged. Pair with `migration_target_version` to indicate when the canonical is expected to be removed. Distinct from `experimental`: an experimental canonical may stabilize and stop being experimental; a deprecated canonical is on a sunset path.
2269
+ */
2270
+ deprecated?: boolean;
2271
+ /**
2272
+ * Whether this canonical has any v1 named-format equivalent. `true` (default) — the canonical is structurally expressible as one or more v1 named formats (IAB display sizes, VAST tags, DAAST tags, etc.); v1→v2 projection via `v1-canonical-mapping.json` is meaningful. `false` — the canonical is inherently new in v2 and has no v1 form; v1's `list_creative_formats` couldn't express it because the underlying concept (algorithmic surface composition, AI-surface mentions, retail-media catalog placements, multi-card carousels) didn't exist as a v1 named-format archetype.
2273
+ *
2274
+ * Lets SDKs distinguish two failure modes that today look identical: (a) the registry hasn't covered this canonical yet (correctable — seller adds explicit `canonical` field or files a registry entry) vs (b) no v1 path is possible (informational — buyer needs v2-aware consumption, or seller declares `canonical_formats_only: true` on the product declaration). SDKs encountering `v1_translatable: false` on a canonical SHOULD NOT emit `FORMAT_PROJECTION_FAILED` (which signals registry-coverage gap) — instead surface the inherent v1-unreachability as a different diagnostic or skip silently. The 4 inherently-v2 canonicals at 3.1 GA: `image_carousel`, `sponsored_placement`, `responsive_creative`, `agent_placement`.
2275
+ */
2276
+ v1_translatable?: boolean;
2277
+ /**
2278
+ * AdCP MAJOR.MINOR version that introduced this canonical (e.g., '3.1', '3.2'). Lets adopters reason about minimum protocol version requirements when consuming a format declaration. Patch precision is intentionally rejected — canonicals are introduced at minor-version boundaries.
2279
+ */
2280
+ since_version?: string;
2281
+ /**
2282
+ * AdCP MAJOR.MINOR version by which the working group expects this canonical to stabilize, surface a breaking revision, or (when `deprecated: true`) be removed. Patch precision is intentionally rejected — canonicals shift at minor-version boundaries. Absence signals 'no specific target' (omit the field rather than use a placeholder like 'unknown').
2283
+ */
2284
+ migration_target_version?: string;
2285
+ /**
2286
+ * Whether the surface composes deterministically (buyer can predict per-slot rendering — sponsored_placement, image, video) or algorithmically (surface chooses combinations or phrasing — responsive_creative, agent_placement).
2287
+ */
2288
+ composition_model?: 'deterministic' | 'algorithmic';
2289
+ /**
2290
+ * When true, the product rejects unsigned synthesized assets. Builders calling build_creative MUST attach a C2PA-compatible provenance manifest attributing synthesis to the creative agent.
2291
+ */
2292
+ provenance_required?: boolean;
2293
+ /**
2294
+ * Platform-specific extensions narrowing the canonical (pixel ID shapes, conversion event taxonomies, platform-specific CTAs/destinations). Each extension is a URI+digest reference resolved against the bundled `extensions` map in get_products responses or fetched directly.
2295
+ *
2296
+ * **Collision precedence (normative).** When two or more `platform_extensions[]` entries on the same declaration extend the same target (e.g., both extend `tracking`) with overlapping field names, **array order is authoritative — later entries override earlier ones on a per-field basis** (last-in-array-wins). SDKs MUST surface the overlap via the `errors[]` array on the `get_products` response with a structured code (`FORMAT_DECLARATION_DIVERGENT` is appropriate when the overlap appears across dual-emitted shapes; a producer-self-emitted overlap on a single declaration SHOULD use the same code with `error.details: { collision_kind: "platform_extension_field", target, overlapping_fields, winning_extension_uri }`). Producers SHOULD avoid the collision by emitting one extension per target or by partitioning fields across extensions; the deterministic precedence is for last-resort consistency across SDK implementations, not a sanctioned merging strategy.
2297
+ */
2298
+ platform_extensions?: PlatformExtensionReference[];
2299
+ /**
2300
+ * When true, the format's production pipeline is genuinely nondeterministic — the platform cannot guarantee that synthesis from a given input set produces in-spec output. Veo / Sora / Runway-class generative video, and other AI-synthesis flows where output dimensions, duration, or quality vary per run. Implies a different validation contract: predictive `validate_input` is impossible; the platform's own post-synthesis QA loop applies; if the QA loop exhausts without producing a valid artifact, `build_creative` returns task_failed with a synthesis_failed reason. Distinct from `composition_model` (which describes how the surface composes per-slot rendering, not whether synthesis is deterministic). When false or absent, the format's production is predictable enough that `validate_input` can predict output properties from input properties.
2301
+ *
2302
+ * **Compatibility with `asset_source` / `item_production_model`**: `synthesis_nondeterministic: true` MAY pair with any of `seller_pre_rendered_from_brief`, `seller_human_designed`, or `agent_synthesized` (the QA loop is concept-level, not source-specific — 'seller renders from brief but each retry differs' is just as nondeterministic as Veo). It MUST NOT pair with `buyer_uploaded` (the buyer ships pre-rendered bytes; there's no synthesis step to be nondeterministic about). It MUST NOT pair with `publisher_host_recorded` (the publisher's host produces a deterministic-from-script output even if the human voice varies). When `synthesis_nondeterministic: true` is set with an incompatible source, validators SHOULD reject with a structured error.
2303
+ */
2304
+ synthesis_nondeterministic?: boolean;
2305
+ /**
2306
+ * Default slots for video_vast canonical. Buyer ships a VAST tag (URL or inline XML, VAST 2.x-4.x) plus an optional clickthrough URL (which falls back to the VAST `ClickThrough` element when omitted). Tracking events are inherent to VAST and don't require explicit slots.
2307
+ */
2308
+ slots?: unknown;
2309
+ /**
2310
+ * Typical production turnaround in business days when the format requires seller-side production (e.g., host-recording from a buyer-supplied script). 0 for synchronous (e.g., generative AI); >0 for human-produced (e.g., podcast host-read). Absent when no production is required (buyer uploads complete creative).
2311
+ */
2312
+ production_window_business_days?: number;
2313
+ orientation?: 'vertical' | 'horizontal' | 'square';
2314
+ /**
2315
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
2316
+ */
2317
+ aspect_ratio?: string;
2318
+ /**
2319
+ * Required VAST version.
2320
+ */
2321
+ vast_version?: '2.0' | '3.0' | '4.0' | '4.1' | '4.2';
2322
+ /**
2323
+ * Whether VPAID interactivity is supported. When true, the VAST tag may carry VPAID JS/Flash payloads.
2324
+ */
2325
+ vpaid_enabled?: boolean;
2326
+ vpaid_version?: '1.0' | '2.0';
2327
+ /**
2328
+ * Whether IAB SIMID interactive video extensions are supported.
2329
+ */
2330
+ simid_supported?: boolean;
2331
+ /**
2332
+ * [min, max] duration in milliseconds. **Precedence**: `duration_ms_exact` takes precedence when both ship. SDKs SHOULD lint a warning when both fields ship.
2333
+ */
2334
+ duration_ms_range?: number[];
2335
+ /**
2336
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship.
2337
+ * @minimum 1
2338
+ */
2339
+ duration_ms_exact?: number;
2340
+ /**
2341
+ * @minimum 1
2342
+ */
2343
+ min_width?: number;
2344
+ /**
2345
+ * @minimum 1
2346
+ */
2347
+ max_width?: number;
2348
+ /**
2349
+ * @minimum 1
2350
+ */
2351
+ min_height?: number;
2352
+ /**
2353
+ * @minimum 1
2354
+ */
2355
+ max_height?: number;
2356
+ /**
2357
+ * Whether the VAST creative must be linear (non-skippable in-stream).
2358
+ */
2359
+ linear_required?: boolean;
2360
+ /**
2361
+ * When skippable, the buyer-side skip threshold in milliseconds (e.g., 5000 for 5-second skippable pre-roll).
2362
+ * @minimum 0
2363
+ */
2364
+ skippable_after_ms?: number;
2365
+ /**
2366
+ * Maximum VAST wrapper redirect depth permitted.
2367
+ * @minimum 0
2368
+ */
2369
+ max_wrapper_depth?: number;
2370
+ ssl_required?: boolean;
2371
+ }
2372
+
2373
+ /**
2374
+ * Cloud storage protocol
2375
+ */
2376
+ export type CloudStorageProtocol = 's3' | 'gcs' | 'azure_blob';
2377
+
2378
+ /**
2379
+ * Opaque correlation data that is echoed unchanged in responses. Used for internal tracking, UI session IDs, trace IDs, and other caller-specific identifiers that don't affect protocol behavior. Context data is never parsed by AdCP agents - it's simply preserved and returned.
2380
+ */
2381
+ export interface ContextObject {
2382
+ }
2383
+
2384
+ /**
2385
+ * Adopter-defined shape that doesn't fit the 12 canonicals. Requires `format_shape` (vocabulary-registered global pattern) and `format_schema` (URI+digest reference to a fetchable schema describing the actual params/slots). `params` shape is governed by the fetched schema rather than baked into AdCP — kept as `type: object` here with `additionalProperties: true` because the canonical schema validates dynamically post-fetch.
2386
+ */
2387
+ export interface CustomFormatDeclaration {
2388
+ format_kind: 'custom';
2389
+ /**
2390
+ * Custom shape's params. Validated against the schema fetched from `format_schema.uri` at the cached `format_schema.digest`.
2391
+ */
2392
+ params: {};
2393
+ }
2394
+
2395
+ export interface DAASTAudioFormatDeclaration {
2396
+ format_kind: 'audio_daast';
2397
+ params: CanonicalFormatDAASTAudio;
2398
+ }
2399
+
2400
+ export interface DisplayTagFormatDeclaration {
2401
+ format_kind: 'display_tag';
2402
+ params: CanonicalFormatDisplayTag;
2403
+ }
2404
+
2405
+ /**
2406
+ * A time duration expressed as an interval and unit. Used for frequency cap windows, attribution windows, reach optimization windows, time budgets, and other time-based settings. When unit is 'campaign', interval must be 1 — the window spans the full campaign flight.
2407
+ */
2408
+ export interface Duration {
2409
+ /**
2410
+ * Number of time units. Must be 1 when unit is 'campaign'.
2411
+ * @minimum 1
2412
+ */
2413
+ interval: number;
2414
+ /**
2415
+ * Time unit. 'seconds' for sub-minute precision. 'campaign' spans the full campaign flight.
2416
+ */
2417
+ unit: 'seconds' | 'minutes' | 'hours' | 'days' | 'campaign';
2418
+ }
2419
+
2420
+ /**
2421
+ * Standard marketing event types for event logging, aligned with IAB ECAPI
2422
+ */
2423
+ export type EventType = 'page_view' | 'view_content' | 'select_content' | 'select_item' | 'search' | 'share' | 'add_to_cart' | 'remove_from_cart' | 'viewed_cart' | 'add_to_wishlist' | 'initiate_checkout' | 'add_payment_info' | 'purchase' | 'refund' | 'lead' | 'qualify_lead' | 'close_convert_lead' | 'disqualify_lead' | 'complete_registration' | 'subscribe' | 'start_trial' | 'app_install' | 'app_launch' | 'contact' | 'schedule' | 'donate' | 'submit_application' | 'custom';
2424
+
2425
+ /**
2426
+ * Extension object for platform-specific, vendor-namespaced parameters. Extensions are always optional and must be namespaced under a vendor/platform key (e.g., ext.gam, ext.roku). Used for custom capabilities, partner-specific configuration, and features being proposed for standardization.
2427
+ */
2428
+ export interface ExtensionObject {
2429
+ }
2430
+
2431
+ export interface Fixed {
2432
+ [k: string]: unknown | undefined;
2433
+ }
2434
+
2435
+ /**
2436
+ * A JSON object — never a plain string — that identifies a creative format by its declaring agent and local slug. Required properties: agent_url (URI of the agent that owns the format) and id (slug matching [a-zA-Z0-9_-]+). Example: {"agent_url": "https://creative.adcontextprotocol.org", "id": "display_300x250"}. Can reference: (1) a concrete format with fixed dimensions (id only), (2) a template format without parameters (id only), or (3) a template format with parameters (id + dimensions/duration). Template formats accept parameters in format_id while concrete formats have fixed dimensions in their definition. Parameterized format IDs create unique, specific format variants. Using a plain string here is a schema violation.
2437
+ */
2438
+ export interface FormatReferenceStructuredObject {
2439
+ /**
2440
+ * URL of the agent that defines this format (e.g., 'https://creative.adcontextprotocol.org' for standard formats, or 'https://publisher.com/.well-known/adcp/sales' for custom formats). Callers comparing two `format-id` values MUST canonicalize `agent_url` per the AdCP URL canonicalization rules before treating two formats as the same. See docs/reference/url-canonicalization.
2441
+ */
2442
+ agent_url: string;
2443
+ /**
2444
+ * Format identifier within the agent's namespace (e.g., 'display_static', 'video_hosted', 'audio_standard'). When used alone, references a template format. When combined with dimension/duration fields, creates a parameterized format ID for a specific variant.
2445
+ * @pattern ^[a-zA-Z0-9_-]+$
2446
+ */
2447
+ id: string;
2448
+ /**
2449
+ * Width in pixels for visual formats. When specified, height must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.
2450
+ * @minimum 1
2451
+ */
2452
+ width?: number;
2453
+ /**
2454
+ * Height in pixels for visual formats. When specified, width must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.
2455
+ * @minimum 1
2456
+ */
2457
+ height?: number;
2458
+ /**
2459
+ * Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.
2460
+ * @minimum 1
2461
+ */
2462
+ duration_ms?: number;
2463
+ }
2464
+
2465
+ export interface HTML5FormatDeclaration {
2466
+ format_kind: 'html5';
2467
+ params: CanonicalFormatHTML5Banner;
2468
+ }
2469
+
2470
+ export interface HostedAudioFormatDeclaration {
2471
+ format_kind: 'audio_hosted';
2472
+ params: CanonicalFormatHostedAudio;
2473
+ }
2474
+
2475
+ export interface HostedVideoFormatDeclaration {
2476
+ format_kind: 'video_hosted';
2477
+ params: CanonicalFormatHostedVideo;
2478
+ }
2479
+
2480
+ /**
2481
+ * Seller honors idempotency_key replay protection on mutating requests. Replays within replay_ttl_seconds return the cached response (or IDEMPOTENCY_CONFLICT on payload divergence); replays past the window return IDEMPOTENCY_EXPIRED when the seller can still distinguish 'seen and evicted' from 'never seen'.
2482
+ */
2483
+ export interface IdempotencySupported {
2484
+ /**
2485
+ * Discriminator. True means the seller deduplicates replays — a repeat of the same idempotency_key within replay_ttl_seconds returns the cached response without re-executing side effects.
2486
+ */
2487
+ supported: true;
2488
+ /**
2489
+ * How long the seller retains a canonical response for an idempotency_key. Within this window, a replay with the same key + equivalent canonical payload returns the cached response; a replay with a different canonical payload returns IDEMPOTENCY_CONFLICT; a replay past the window returns IDEMPOTENCY_EXPIRED when the seller can still distinguish 'seen and evicted' from 'never seen'. Minimum 3600 (1h); recommended 86400 (24h). Maximum 604800 (7 days) — longer windows force buyers to retain secret keys at rest for extended periods and grow the seller's cache table without bounded benefit.
2490
+ * @minimum 3600
2491
+ * @maximum 604800
2492
+ */
2493
+ replay_ttl_seconds: number;
2494
+ /**
2495
+ * Maximum lifetime in seconds of an in-flight idempotency row before the seller releases it per L1/security.mdx rule 9 (treat the in-flight attempt as failed if the handler does not complete within this bound). Buyer SDKs use this value to compute a retry budget when they see `IDEMPOTENCY_IN_FLIGHT` — cap individual retry waits at this value rather than the much-wider `replay_ttl_seconds` ceiling. Optional in 3.1 (additive declaration); SDKs that don't see the field fall back to rule 9's order-of-magnitude SHOULD heuristic. Required when `supported: true` in 4.0. MUST be no greater than `replay_ttl_seconds` (a bound larger than the replay window is vacuous — any retry past the TTL hits IDEMPOTENCY_EXPIRED regardless of in-flight state); validators MUST enforce this cross-field constraint at the test layer since JSON Schema cannot express field-relative bounds. A buyer that observes `error.details.retry_after` exceeding this value MAY treat that as a seller bug — the in-flight row cannot legitimately outlive the bound the seller declared.
2496
+ * @minimum 1
2497
+ * @maximum 604800
2498
+ */
2499
+ in_flight_max_seconds?: number;
2500
+ /**
2501
+ * When true, the seller derives `account_id` via an HKDF-based one-way transform of the buyer's natural account key rather than echoing the natural key on the wire. Buyers MUST NOT attempt to invert the opaque id and MUST treat it as a blind handle scoped to this seller. Absent or false, callers should assume `account_id` is the natural key (or a server-assigned but non-opaque id). This flag does not change the wire shape, but it DOES change buyer behavior — buyers MUST NOT cache, log, or treat `account_id` as a natural-key analog when this flag is true. Migration note for sellers already returning an opaque id without this flag: set it to true at the next capabilities refresh so buyers stop inferring natural-key semantics; until set, new-buyer replay/retry logic will misclassify these ids as natural keys.
2502
+ */
2503
+ account_id_is_opaque?: boolean;
2504
+ }
2505
+
2506
+ /**
2507
+ * Seller does NOT honor idempotency_key replay protection — sending a key is a no-op, the seller will NOT return IDEMPOTENCY_CONFLICT or IDEMPOTENCY_EXPIRED, 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 this seller. replay_ttl_seconds and in_flight_max_seconds MUST be absent — they have no meaning without replay support.
2508
+ */
2509
+ export interface IdempotencyUnsupported {
2510
+ /**
2511
+ * Discriminator. False means the seller does not deduplicate retries.
2512
+ */
2513
+ supported: false;
2514
+ }
2515
+
2516
+ export interface ImageCarouselFormatDeclaration {
2517
+ format_kind: 'image_carousel';
2518
+ params: CanonicalFormatImageCarousel;
2519
+ }
2520
+
2521
+ export interface ImageFormatDeclaration {
2522
+ format_kind: 'image';
2523
+ params: CanonicalFormatImage;
2524
+ }
2525
+
2526
+ /**
2527
+ * Keyword targeting match type. broad: ads may serve on queries semantically related to the keyword. phrase: ads serve when the query contains the keyword phrase. exact: ads serve only when the query matches the keyword exactly.
2528
+ */
2529
+ export type MatchType = 'broad' | 'phrase' | 'exact';
2530
+
2531
+ /**
2532
+ * Filter to products from sellers supporting specific protocol features. Only features set to true are used for filtering.
2533
+ */
2534
+ export interface MediaBuyFeatures {
2535
+ /**
2536
+ * Supports creatives provided inline in create_media_buy requests
2537
+ */
2538
+ inline_creative_management?: boolean;
2539
+ /**
2540
+ * Honors property_list parameter in get_products to filter results to buyer-approved properties
2541
+ */
2542
+ property_list_filtering?: boolean;
2543
+ /**
2544
+ * Supports sync_catalogs task for catalog feed management with platform review and approval
2545
+ */
2546
+ catalog_management?: boolean;
2547
+ /**
2548
+ * Seller has per-package snapshot infrastructure for the reporting contract. When true, the seller MUST populate `package.committed_metrics` on every `create_media_buy` response and MUST honor append-only mid-flight metric additions via `update_media_buy`. The unified `committed_metrics` array (per the metric-accountability design) covers both standard and vendor-defined metric entries, so a single flag is load-bearing. Buyers filtering on this flag are detecting 'this seller can stamp the reporting contract,' which closes the audit gap from PR #3510 where absence of `committed_metrics` was indistinguishable between 'didn't snapshot' and 'snapshot infrastructure not implemented.'
2549
+ */
2550
+ committed_metrics_supported?: boolean;
2551
+ [k: string]: boolean | undefined;
2552
+ }
2553
+
2554
+ /**
2555
+ * Standardized advertising media channels describing how buyers allocate budget. Channels are planning abstractions, not technical substrates. See the Media Channel Taxonomy specification for detailed definitions.
2556
+ */
2557
+ export type MediaChannel = 'display' | 'olv' | 'social' | 'search' | 'ctv' | 'linear_tv' | 'radio' | 'streaming_audio' | 'podcast' | 'dooh' | 'ooh' | 'print' | 'cinema' | 'email' | 'gaming' | 'retail_media' | 'influencer' | 'affiliate' | 'product_placement' | 'sponsored_intelligence';
2558
+
2559
+ export interface MultiSize {
2560
+ [k: string]: unknown | undefined;
2561
+ }
2562
+
2563
+ export interface NativeInFeedFormatDeclaration {
2564
+ format_kind: 'native_in_feed';
2565
+ params: CanonicalFormatNativeInFeed;
2566
+ }
2567
+
2568
+ export interface None {
2569
+ [k: string]: unknown | undefined;
2570
+ }
2571
+
2572
+ /**
2573
+ * REQUIRED when `format_kind: "custom"`; otherwise MUST be absent. URI+digest reference to a fetchable schema describing this custom shape's actual `params` and `slots`. Same hosting model as `platform_extensions`: open-ecosystem publishers host the artifact at the canonical URI on their subdomain; closed-platform / walled-garden shapes resolve through the AAO mirror at `https://creative.adcontextprotocol.org/translated/...`. Buyer agents fetch by `uri@digest` (immutable per digest, aggressive caching, `Cache-Control: public, max-age=31536000, immutable`), validate `params` and `slots` against the fetched schema, and reason about manifests structurally — same mechanic as platform_extensions but at the format-structure level. Without `format_schema`, custom shapes would be opaque to buyer agents and the protocol would regress to per-seller integration code; that's why the schema is required, not optional.
2574
+ *
2575
+ * **Fetch contract (normative)** — `format_schema` is load-bearing for validation (unlike `platform_extensions`, which is informational on the *consumption* side). The *transport* rules below apply identically to BOTH fields — any SDK fetching a `platform-extension-ref.json` URI MUST apply this contract regardless of whether the field name is `format_schema` or `platform_extensions`. A shared SDK fetch path that drops to the weakest bar undermines `format_schema`'s hardening. The consumption distinction (load-bearing vs informational) is about *what the body means*; the transport distinction is `https`-and-allowlisted regardless.
2576
+ *
2577
+ * - **Transport**: `https` only. Buyers MUST reject `http://`, `file://`, `data:`, and any non-`https` scheme. The URI MUST resolve to a JSON document that is itself a valid JSON Schema (Draft 07 or 2020-12; producers MUST declare `$schema`).
2578
+ * - **SSRF protection**: buyers MUST resolve the URI hostname and reject if any resolved address is in RFC 1918 private space (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`), loopback (`127.0.0.0/8`, `::1`), link-local (`169.254.0.0/16`, `fe80::/10`), CGNAT (`100.64.0.0/10`), or any RFC 6761 special-use name (`.local`, `.localhost`, `.internal`, `.test`, `.example`, `.invalid`). Cloud metadata endpoints (`169.254.169.254`, `metadata.google.internal`, `kubernetes.default.svc`) are explicitly forbidden — these are credential-leak primitives. Buyers MUST pin the connection to the resolved IP (or re-resolve and re-validate the allowlist per request) to defeat DNS rebinding.
2579
+ * - **HTTP redirects**: MUST be disabled. If a follow is implemented at all, the redirect target MUST pass the same scheme + SSRF + allowlist checks; otherwise the fetch hard-fails. Open redirects on same-origin paths are otherwise a free SSRF primitive.
2580
+ * - **Response size cap**: response body MUST be capped at 1 MiB. Enforce during streaming, not after full buffering. Over-cap hard-fails identically to digest mismatch.
2581
+ * - **Timeout**: SDKs SHOULD apply a fetch timeout ≤5 seconds. Timeout SHOULD be treated identically to an HTTP 5xx response (transient — retry policy at the SDK's discretion; on persistent failure surface as unresolved and skip the declaration for this session).
2582
+ * - **Digest verification**: SHA-256 of the response body MUST equal `digest`. **Digest mismatch is a hard fail** — the buyer MUST treat the format declaration as unresolvable and MUST NOT validate manifests against the mismatched body. A divergent digest is either a malicious substitution or producer error; either way, falling back to the un-verified body breaks the trust model. Digest format: `sha256:` prefix + 64 lowercase hex characters. Cache key is `uri@digest`; digest mismatch MUST NOT be cached as a negative result keyed on `uri` alone (defeats CDN-flap recovery), and MUST be distinguishable in telemetry from network 5xx / 404 (sustained mismatch is a substitution-attack signal, not a flap).
2583
+ * - **Sandboxing of `$ref`**: fetched schemas MAY use `$ref`. Buyers MUST resolve `$ref` only to URIs that are (a) same-origin as the parent `format_schema.uri` after RFC 3986 §6 normalization (lowercase scheme + host, strip default port, normalize path dot-segments, no userinfo component), OR (b) hosted under the AAO catalog domain (`https://creative.adcontextprotocol.org/...`), OR (c) intra-document JSON Pointer refs (`#/...`) bounded to the parent document's parsed tree. Cross-origin `$ref` to arbitrary URIs MUST be rejected. `$ref: file://...` MUST be rejected unconditionally. Transitive `$ref` chains MUST be bounded at depth ≤8 AND `$ref` count ≤256 across the resolved tree (depth 8 with breadth 100 per level is 10^16 nodes — depth alone is not enough). Publishers SHOULD inline rather than $ref where possible.
2584
+ * - **Schema-compile bounds (DoS protection)**: validators MUST bound CPU/memory on fetched schemas. Recommended: compiled-schema keyword count ≤10 000, `pattern` regexes evaluated with a non-backtracking engine (re2) OR under a per-pattern timeout, per-manifest validation budget ≤250 ms (exceeded budget → treat manifest as invalid, surface telemetry signal). Without these, a 'valid' schema with catastrophic regex backtracking or exponential `allOf`/`anyOf` expansion pins a CPU forever.
2585
+ * - **Cache**: buyers cache fetched schemas by `uri@digest` and treat them as immutable (the same hosting contract as `platform_extensions`). On `404`, network partition, or persistent fetch failure, buyers SHOULD degrade gracefully (treat the declaration as unresolved, skip it for the current `get_products` response, surface via `errors[]` with the relevant code) rather than failing the entire session.
2586
+ * - **Schema-not-valid handling**: if the fetched body parses as JSON but is not a valid JSON Schema, the buyer MUST treat the declaration as unresolvable (same as digest mismatch) and surface via `errors[]`. Validators MUST NOT attempt partial validation against an invalid schema.
2587
+ * - **AAO catalog trust**: `https://creative.adcontextprotocol.org/*` is a single trust anchor in the same-origin allowlist; compromise of the catalog domain or its CA compromises every buyer agent. Catalog-served bodies MUST be digest-pinned identically to origin fetches (the digest is on the *parent* `format_schema.uri@digest`, not on the catalog response). Future hardening (signed bodies, transparency log) is tracked separately.
2588
+ */
2589
+ export interface PlatformExtensionReference {
2590
+ /**
2591
+ * HTTPS URL identifying the extension. `https://` is mandatory — `http://`, `file://`, `data:`, and other schemes are rejected at the schema layer (defense-in-depth on top of the fetch-contract normative rules). The URI base is the owning agent's URL; the path identifies the extension within that agent. Example: 'https://creative.adcontextprotocol.org/translated/meta/extensions/meta_pixel'. The full fetch contract — SSRF allowlist, response-size cap, $ref sandbox, schema-compile bounds — is documented on `product-format-declaration.json#format_schema` and applies to ALL fetches of this reference shape regardless of whether the field is named `format_schema` (load-bearing for validation) or `platform_extensions` (informational); the *transport* rules are identical, only the *consumption* semantics differ.
2592
+ * @pattern ^https:\/\/
2593
+ */
2594
+ uri: string;
2595
+ /**
2596
+ * SHA-256 content digest of the extension definition (sha256:<hex>). Used to detect drift — if the agent revises the extension, the digest changes and cached definitions become invalid.
2597
+ * @pattern ^sha256:[a-f0-9]{64}$
2598
+ */
2599
+ digest: string;
2600
+ }
2601
+
2602
+ /**
2603
+ * Pricing model used for this media buy
2604
+ */
2605
+ export type PricingModel = 'cpm' | 'vcpm' | 'cpc' | 'cpcv' | 'cpv' | 'cpp' | 'cpa' | 'flat_rate' | 'time';
2606
+
2607
+ /**
2608
+ * Inline format declaration on a product. The `format_kind` discriminator names which canonical format the product narrows; `params` carries the canonical's parameter schema (slots, dimensions, durations, codecs, character limits, platform_extensions, etc.). Optional `capability_id` (stable identifier for routing when a product's `format_options` contains multiple declarations sharing the same `format_kind`), `display_name` (seller-controlled human-readable label for dashboard and catalog UIs), and `applies_to_channels` (subset of the product's declared channels this declaration applies to — lets a multi-channel product carry distinct format_options per channel). Discriminated-union shape generates clean tagged unions in TypeScript and Pydantic codegen. Replaces v1's named-format pattern (where products referenced a separately-defined format file via compound `format_id`). v1 named formats remain supported through the deprecation cycle; v2 product-bound declarations are opt-in.
2609
+ *
2610
+ * **Closed-set semantics (normative).** `format_options[]` is the closed set of accepted formats for this product. Sellers MUST reject `create_media_buy` requests targeting any `format_kind` (or `capability_id`) not present in this list — typically with `UNSUPPORTED_FEATURE` or a seller-specific code; the rejection is structural, not negotiable. `seller_preference` modulates *within* the accepted set (a soft ranking hint between equally-acceptable options), it is NOT an enforcement axis. A product wanting to say 'this format is the only one that works' lists exactly that one entry in `format_options[]`; everything else falls outside the set and is rejected by the closed-set rule.
2611
+ *
2612
+ * **Custom format_kind** (`format_kind: "custom"`): for adopter-defined shapes that don't fit the 12 canonicals (multi-placement takeover, roadblock, branded content, cross-screen sponsorship, sponsorship lockup, newsletter sponsorship, AR lens, playable, live event sponsorship). When `format_kind` is `custom`, the declaration MUST carry `format_shape` (recognized global pattern from the [format-shape vocabulary registry](/schemas/core/format-shape-vocabulary.json)) AND `format_schema` (URI+digest reference to a fetchable schema describing the actual `params` and `slots`). Buyer agents fetch the schema, validate manifests structurally, and reason about manifests without per-seller integration code. See [adcp#3666](https://github.com/adcontextprotocol/adcp/issues/3666) for the canonical promotion queue.
2613
+ */
2614
+ export type ProductFormatDeclaration = {
2615
+ [k: string]: unknown | undefined;
2616
+ } & {
2617
+ /**
2618
+ * Stable identifier for this format declaration. REQUIRED when the parent product's `format_options` contains multiple declarations sharing the same `format_kind` (so buyers can disambiguate which option a manifest targets via `manifest.capability_id`). SHOULD be set on EVERY `format_options[]` entry — not just when structurally required to break a `format_kind` collision — so V2-mental-model buyers can use the V2 authoring path (`PackageRequest.capability_ids[]`, `creative-manifest.capability_id`) against the product. A product that ships without `capability_id` on its `format_options[]` entries is structurally 3.1-conformant but is not V2-authorable: buyers fall back to v1 `format_ids[]` and lose the cross-publisher-stable naming the V2 path was designed to provide. Sellers MUST reject V2 authoring against such products with `UNSUPPORTED_FEATURE` and `error.details.reason` set to `capability_ids_not_published` per `package-request.json`. The 4.0 cutover will tighten this from SHOULD to MUST (see #4857). Format-internal (not a URI). Examples: 'flashtalking_image_300x250', 'pmax_responsive_search', 'nytimes_homepage_image'.
2619
+ */
2620
+ capability_id?: string;
2621
+ /**
2622
+ * Optional seller-controlled human-readable label for this format declaration. Used by buyer dashboards, catalog UIs, and reporting surfaces to show a seller's own naming ('Homepage Takeover', 'Branded Canvas', 'Reels Premium Video') rather than the raw `format_kind` or `capability_id`. Has no machine semantics — buyer agents route on `format_kind` and `capability_id`; `display_name` is purely for human presentation. Freeform; no enumeration. Sellers SHOULD keep it stable once published to avoid dashboard churn.
2623
+ */
2624
+ display_name?: string;
2625
+ /**
2626
+ * Optional subset of the parent product's `channels` to which this declaration applies. When omitted, the declaration applies to ALL channels declared on the product. Lets a multi-channel product (e.g., `channels: ['display', 'video']`) carry distinct format_options per channel — `format_options: [{format_kind: 'image', applies_to_channels: ['display']}, {format_kind: 'video_hosted', applies_to_channels: ['video']}]`. Buyers ship channel-appropriate manifests per `applies_to_channels`.
2627
+ */
2628
+ applies_to_channels?: MediaChannel[];
2629
+ /**
2630
+ * Optional soft routing hint *within* a product's accepted set of formats — NOT an enforcement axis. `preferred` — seller actively recommends this format (often because of measurement, viewability, or render-quality differences); `accepted` — supported on equal footing with other format_options (default when omitted); `discouraged` — supported but suboptimal (e.g., legacy 3p-tag where the seller would prefer html5 for OM-SDK coverage). Buyer agents picking between format_options SHOULD respect seller preferences when their own constraints don't override.
2631
+ *
2632
+ * **Not an enforcement axis (normative).** `seller_preference` does NOT carry the meaning of 'this format won't work / required-only'. That case is structural: `format_options[]` IS the closed set of accepted formats; anything outside the list is rejected at `create_media_buy` regardless of preference. A seller that accepts only one format lists exactly that one entry — the structural fact does the enforcement work, no enum value needed. There is intentionally no `required` value; preference is bounded to *ranking within the already-accepted set*, not gating into it.
2633
+ */
2634
+ seller_preference?: 'preferred' | 'accepted' | 'discouraged';
2635
+ /**
2636
+ * When true, this format declaration has no clean v1 projection and SDKs MUST NOT synthesize a v1 `format_id` for it. Buyers reading the product on the v1 wire path see this declaration absent from `format_ids`; only v2-aware buyers (reading `format_options`) discover it. Set explicitly for `format_kind: "custom"` declarations (no canonical exists in v1 to project onto) and for declarations whose canonical/parameter shape cannot round-trip through a v1 named format without semantic loss. The protocol does NOT mint synthetic v1 format_ids for unmappable declarations — the alternative (an `aao-synth/*` namespace populated automatically) was considered and rejected because adopters would index on synthetic IDs that have no stable identity. Producers SHOULD set `canonical_formats_only: true` rather than omit the declaration from `format_options` — explicit v2-only is more useful than silent absence.
2637
+ */
2638
+ canonical_formats_only?: boolean;
2639
+ /**
2640
+ * When true, THIS seller's specific product declaration may not work as declared — even if the underlying canonical is stable. Use for beta runtime paths, forward-looking catalog entries the runtime doesn't yet honor, or experimental products where the seller wants buyer-side caution. Buyers reading `experimental: true` on a product declaration SHOULD prefer the v1 path when a v1 fallback exists for the same product (via `format_ids` on the parent product or via this declaration's `v1_format_ref`) and SHOULD validate via `validate_input` or a sandbox before routing production budget.
2641
+ *
2642
+ * Independent of the canonical's own `experimental` flag — a stable canonical (e.g., `image`, `video_hosted`) can carry an experimental product declaration when the seller is shipping a new runtime path that isn't fully wired yet. Conversely, an experimental canonical (`sponsored_placement`, `responsive_creative`, `agent_placement`) MAY carry non-experimental product declarations where the seller's adopter contract is well-tested. Buyer SDKs SHOULD filter products with `experimental: true` from default views and offer an opt-in flag to surface them.
2643
+ *
2644
+ * Replaces the earlier `runtime_status` enum (`stable | preview | declared_only`) — same semantic ('use with caution') without the cognitive overhead of two stability axes.
2645
+ */
2646
+ experimental?: boolean;
2647
+ /**
2648
+ * REQUIRED when `format_kind: "custom"`; otherwise MUST be absent. Recognized global pattern this custom shape is an instance of, drawn from the [format-shape vocabulary registry](/schemas/core/format-shape-vocabulary.json) (`multi_placement_takeover`, `roadblock`, `branded_content`, `cross_screen_sponsorship`, `sponsorship_lockup`, `newsletter_sponsorship`, `ar_lens`, `playable`, `live_event_sponsorship`, …). Non-canonical values valid (validators MAY soft-warn) — adopters CAN ship a shape that isn't yet in the registry. Adding entries is a vocabulary PR. Once a `format_shape` entry sees 2+ adopters with substantively similar `format_schema` content for 90+ days, the working group promotes it to a first-class canonical.
2649
+ */
2650
+ format_shape?: string;
2651
+ /**
2652
+ * Authoritative v2 → v1 link, expressed as an array of one or more v1 `format_id` ({agent_url, id}) values. Each entry asserts that this canonical-formats declaration IS the same underlying format as the referenced v1 named format. Always an array (single-ref is `[{...}]`) so the multi-size case below has a clean wire shape — adopters surveyed in the SDK implementor review pushed for this over the lossy single-ref form.
2653
+ *
2654
+ * The v2 declaration's `params` MUST narrow (be compatible with) each referenced v1 format's `requirements` — see the 'Narrows — formal definition' section in canonical-formats.mdx. SDKs comparing dual-emitted shapes (`Product.format_ids[]` ⊇ entries from `v1_format_ref` AND `Product.format_options[]` carrying this declaration) treat the link as the authoritative pairing and run the narrowing check between this declaration and EACH referenced v1 format file's `requirements`.
2655
+ *
2656
+ * **Multi-size fan-out (normative).** When the declaration carries `params.sizes: [{w,h}, ...]` (multi-size flexible slot), sellers SHOULD carry one `v1_format_ref[]` entry per size, each pointing at the per-size v1 named format in the AAO catalog. Example: a multi-size image declaration with `sizes: [300x250, 728x90, 970x250]` SHOULD carry `v1_format_ref: [{aao, display_300x250_image}, {aao, display_728x90_image}, {aao, display_970x250_image}]`. v1-only buyers then see the product on all three sizes via the `format_ids[]` dual-emission. When `v1_format_ref[]` count < `sizes[]` count, SDKs MUST emit `FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE` on the response `errors[]` (advisory, alongside the partial-coverage v1 emit — NOT in place of it). SDKs MAY (non-normative) fan out automatically by catalog lookup when `v1_format_ref[]` has length 1 and `sizes[]` has length N — opt-in, requires catalog access; sellers asserting refs is the source of truth.
2657
+ *
2658
+ * Mutually exclusive with `canonical_formats_only: true` — a declaration can EITHER assert no v1 projection (`canonical_formats_only: true`) OR link to v1 named formats (`v1_format_ref[]`), never both. When neither is present, SDKs fall back to the resolution order in `v1-canonical-mapping.json` (seller's explicit `canonical` field on the v1 file → registry glob → structural match → fail-closed).
2659
+ *
2660
+ * This is the v2-side authoritative replacement for the v1-side `canonical_parameters` field on `format.json` (which is deprecated for 3.1, removed at 4.0). Sellers SHOULD prefer authoring v2 declarations with `v1_format_ref[]` over mirroring the v2 shape onto v1 files via `canonical_parameters`; the directional link (v2 declaration → v1 identifiers) is the same fact without the parallel-shape drift surface.
2661
+ *
2662
+ * **AAO-hosted convention (normative).** For IAB-standard formats (image dimensions, VAST/DAAST tags, standard third-party tags, HTML5 banner bundles), sellers SHOULD point each `v1_format_ref[].agent_url` at the AAO-hosted canonical agent URL `https://creative.adcontextprotocol.org` and use the registry-published id (e.g., `display_300x250_image`, `video_vast_30s`, `audio_standard_30s`, `display_300x250_html`, `display_js`). This converges the v1-wire namespace: every seller's IAB MREC points at the same `{agent_url, id}` pair, so v1-only buyers' allowlists work uniformly. Without this convention, every publisher's 300x250 ships with a different `v1_format_ref` (theirs vs nytimes.example vs cnn.example vs …) and the v1 wire fragments into per-publisher namespaces — exactly what canonical-formats was designed to eliminate.
2663
+ *
2664
+ * For platform-specific formats (Meta Reels, TikTok Spark, Snap Spotlight, etc.), each `v1_format_ref[].agent_url` SHOULD point at the platform's own agent_url when the platform has adopted AdCP and publishes its own `adagents.json` with `formats[]`. When the platform has NOT adopted AdCP, sellers SHOULD point at the AAO community-registry mirror — `https://creative.adcontextprotocol.org/translated/<platform>` + `id: <platform-format-name>` (e.g., `https://creative.adcontextprotocol.org/translated/meta` + `id: meta_reels`). This keeps the v1 namespace converged across all sellers selling that platform's inventory until the platform owns its own adagents.json.
2665
+ *
2666
+ * **Platform-adoption cutover (normative).** When a platform adopts AdCP and publishes its own adagents.json, sellers MUST update `v1_format_ref[].agent_url` to the platform's adopted agent_url in the same minor release as the AAO mirror entry's `superseded_by` field goes live (see `static/schemas/source/adagents.json#superseded_by`). The AAO mirror entry SHOULD continue serving for ≥1 minor release after `superseded_by` is set, returning an advisory 'superseded' marker so v1 buyer allowlists keyed on the mirror URL get an explicit signal rather than a silent break. **Identity-confusion note**: the mirror URL is *format-shape namespace*, NOT seller identity. Inventory authorization always flows from `authorized_agents[]` + publisher signing keys; a buyer matching `v1_format_ref[].agent_url` against an allowlist is matching format-shape provenance, not seller identity.
2667
+ *
2668
+ * **Mirror domain migration (3.1).** Earlier drafts used `https://mirror.adcontextprotocol.org/translated/<platform>`. As of this release, the convention is `https://creative.adcontextprotocol.org/translated/<platform>` — sibling content under the AAO catalog domain we already host. Adopters who hardcoded the earlier mirror URL MUST migrate to the new path; the canonical-formats.mdx migration section documents the move. No transitional redirect is currently published (the earlier subdomain was never provisioned).
2669
+ *
2670
+ * For seller-bespoke formats (a publisher's `acme_homepage_takeover` that doesn't fit IAB conventions), each `v1_format_ref[].agent_url` is the seller's own agent_url and the id is seller-namespaced. These won't appear in `v1-canonical-mapping.json`'s registry; they're seller-asserted only.
2671
+ */
2672
+ v1_format_ref?: FormatReferenceStructuredObject[];
2673
+ format_schema?: PlatformExtensionReference;
2674
+ } & (ImageFormatDeclaration | HTML5FormatDeclaration | DisplayTagFormatDeclaration | ImageCarouselFormatDeclaration | HostedVideoFormatDeclaration | VASTVideoFormatDeclaration | HostedAudioFormatDeclaration | DAASTAudioFormatDeclaration | SponsoredPlacementFormatDeclaration | NativeInFeedFormatDeclaration | ResponsiveCreativeFormatDeclaration | AgentPlacementFormatDeclaration | CustomFormatDeclaration);
2675
+
2676
+ /**
2677
+ * Push notification configuration for async task updates (A2A and REST protocols). Echoed from the request to confirm webhook settings. Specifies URL, authentication scheme (Bearer or HMAC-SHA256), and credentials. MCP uses progress notifications instead of webhooks.
2678
+ */
2679
+ export interface PushNotificationConfig {
2680
+ /**
2681
+ * Webhook endpoint URL for task status notifications. The wire contract is unconstrained beyond `format: "uri"` — in particular, publishers SHOULD NOT enforce a destination-port allowlist by default, since buyers legitimately host receivers on non-standard TLS ports (`:9443`, `:4443`, path-routed multi-tenant gateways). The SSRF guard the protocol relies on is the IP-range check + DNS-rebinding-resistant connect pin defined in [Webhook URL validation (SSRF)](/docs/building/by-layer/L1/security#webhook-url-validation-ssrf), not port filtering. Operators who want a hardened destination-port allowlist as defense-in-depth (e.g., locked-down enterprise egress) opt in explicitly — see [Destination port: permissive by default](/docs/building/by-layer/L1/security#destination-port-permissive-by-default).
2682
+ */
2683
+ url: string;
2684
+ /**
2685
+ * Buyer-supplied correlation identifier for the operation that will produce webhooks against this registration. The seller MUST echo this value verbatim into every webhook payload's `operation_id` field (see [`mcp-webhook-payload.json`](/schemas/core/mcp-webhook-payload.json) and [Webhooks — Operation IDs](/docs/building/by-layer/L3/webhooks#operation-ids-and-url-templates)). Buyers SHOULD generate a unique value per task invocation (UUID recommended). This field is the canonical registration channel for `operation_id`; buyers MAY additionally embed the same value in the URL path or query as a routing aid for their own HTTP server, but the URL is opaque to the seller and the wire-level source of truth is this field. Sellers MUST NOT parse the URL to recover `operation_id`. Sellers that receive a webhook registration without `operation_id` MAY reject the task with `INVALID_REQUEST`.
2686
+ * @minLength 1
2687
+ * @maxLength 255
2688
+ * @pattern ^[A-Za-z0-9_.:-]{1,255}$
2689
+ */
2690
+ operation_id?: string;
2691
+ /**
2692
+ * Optional client-provided token for webhook validation. The seller MUST echo this value verbatim in every webhook payload's `token` field (see [`mcp-webhook-payload.json`](/schemas/core/mcp-webhook-payload.json) for the receiver-side validation obligation). Length bounds give receivers a defensive range check on the echoed value; senders SHOULD generate tokens with at least 128 bits of entropy (≥22 base64url characters). This is a complementary authenticity mechanism that can layer on top of the RFC 9421 webhook signature — unlike the `authentication` block below, it is not on the 4.0 removal track. Receivers that registered both a signing key (RFC 9421) and a `token` MUST NOT treat a valid token echo as authorization to skip signature verification; both checks remain independent obligations.
2693
+ * @minLength 16
2694
+ * @maxLength 4096
2695
+ */
2696
+ token?: string;
2697
+ /**
2698
+ * Legacy authentication configuration (A2A-compatible). Opts the seller into Bearer or HMAC-SHA256 signing instead of the default RFC 9421 webhook profile. Deprecated; removed in AdCP 4.0. **Precedence is a switch, not a fallback:** presence of this block selects the legacy scheme; absence selects 9421. A seller MUST NOT sign the same webhook both ways, and a buyer MUST NOT attempt 'try 9421 first, fall back to HMAC' verification — signature mode is determined solely by whether this block was present at registration time. The seller's baseline 9421 webhook-signing key published at its brand.json `agents[]` `jwks_uri` does not override this selector; it is always discoverable but only used when `authentication` is omitted. See docs/building/implementation/security.mdx#webhook-callbacks for the full precedence and downgrade-resistance rules (including the `webhook_mode_mismatch` rejection a buyer MUST apply when a received webhook's signing mode does not match the registered mode).
2699
+ */
2700
+ authentication?: {
2701
+ /**
2702
+ * Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for legacy shared-secret signing. Both are deprecated; new integrations SHOULD omit `authentication` and use the RFC 9421 webhook profile.
2703
+ */
2704
+ schemes: AuthenticationScheme[];
2705
+ /**
2706
+ * Credentials for the legacy scheme. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.
2707
+ * @minLength 32
2708
+ */
2709
+ credentials: string;
2710
+ };
2711
+ }
2712
+
2713
+ /**
2714
+ * Unit of measurement for reach and audience_size metrics in this forecast. Required for cross-channel forecast comparison.
2715
+ */
2716
+ export type ReachUnit = 'individuals' | 'households' | 'devices' | 'accounts' | 'cookies' | 'custom';
2717
+
2718
+ export type Responsive = {
2719
+ [k: string]: unknown | undefined;
2720
+ };
2721
+
2722
+ export interface ResponsiveCreativeFormatDeclaration {
2723
+ format_kind: 'responsive_creative';
2724
+ params: CanonicalFormatResponsiveCreative;
2725
+ }
2726
+
2727
+ /**
2728
+ * Type of rights (talent, music, etc.). Helps identify constraints when a creative combines multiple rights types.
2729
+ */
2730
+ export type RightType = 'talent' | 'character' | 'brand_ip' | 'music' | 'stock_media';
2731
+
2732
+ /**
2733
+ * Types of rights usage that can be licensed through the brand protocol. Aligned with DDEX UseType direction for interoperability with music and media rights systems.
2734
+ */
2735
+ export type RightUse = 'likeness' | 'voice' | 'name' | 'endorsement' | 'motion_capture' | 'signature' | 'catchphrase' | 'sync' | 'background_music' | 'editorial' | 'commercial' | 'ai_generated_image';
2736
+
2737
+ /**
2738
+ * What capabilities the host supports
2739
+ */
2740
+ export interface SICapabilities {
2741
+ /**
2742
+ * Interaction modalities supported
2743
+ */
2744
+ modalities?: {
2745
+ /**
2746
+ * Pure text exchange - the baseline modality
2747
+ */
2748
+ conversational?: boolean;
2749
+ /**
2750
+ * Audio-based interaction using brand voice
2751
+ */
2752
+ voice?: boolean | {
2753
+ /**
2754
+ * TTS provider (elevenlabs, openai, etc.)
2755
+ */
2756
+ provider?: string;
2757
+ /**
2758
+ * Brand voice identifier
2759
+ */
2760
+ voice_id?: string;
2761
+ };
2762
+ /**
2763
+ * Brand video content playback
2764
+ */
2765
+ video?: boolean | {
2766
+ /**
2767
+ * Supported video formats (mp4, webm, etc.)
2768
+ */
2769
+ formats?: string[];
2770
+ /**
2771
+ * Maximum video duration
2772
+ */
2773
+ max_duration_seconds?: number;
2774
+ };
2775
+ /**
2776
+ * Animated video presence with brand avatar
2777
+ */
2778
+ avatar?: boolean | {
2779
+ /**
2780
+ * Avatar provider (d-id, heygen, synthesia, etc.)
2781
+ */
2782
+ provider?: string;
2783
+ /**
2784
+ * Brand avatar identifier
2785
+ */
2786
+ avatar_id?: string;
2787
+ };
2788
+ };
2789
+ /**
2790
+ * Visual components supported
2791
+ */
2792
+ components?: {
2793
+ /**
2794
+ * Standard components that all SI hosts must render
2795
+ */
2796
+ standard?: ('text' | 'link' | 'image' | 'product_card' | 'carousel' | 'action_button')[];
2797
+ /**
2798
+ * Platform-specific extensions (chatgpt_apps_sdk, maps, forms, etc.)
2799
+ */
2800
+ extensions?: {};
2801
+ };
2802
+ /**
2803
+ * Commerce capabilities
2804
+ */
2805
+ commerce?: {
2806
+ /**
2807
+ * Supports ACP (Agentic Commerce Protocol) checkout handoff
2808
+ */
2809
+ acp_checkout?: boolean;
2810
+ };
2811
+ /**
2812
+ * A2UI (Agent-to-UI) capabilities
2813
+ */
2814
+ a2ui?: {
2815
+ /**
2816
+ * Supports A2UI surface rendering
2817
+ */
2818
+ supported?: boolean;
2819
+ /**
2820
+ * Supported A2UI component catalogs (e.g., 'si-standard', 'standard')
2821
+ */
2822
+ catalogs?: string[];
2823
+ };
2824
+ /**
2825
+ * Supports MCP Apps for rendering A2UI surfaces in iframes
2826
+ */
2827
+ mcp_apps?: boolean;
2828
+ }
2829
+
2830
+ /**
2831
+ * Exactly one of: (a) fixed (`width` + `height` both set), (b) multi-size (`sizes` set), (c) responsive (any of `min_width`/`max_width`/`min_height`/`max_height` set), (d) none (no size constraint declared — accepts any dimensions). Combining modes (e.g., `width` + `sizes`) is rejected at schema layer; same rule on `html5` and `display_tag` canonicals.
2832
+ */
2833
+ export type SizeModeMutex = Fixed | MultiSize | Responsive | None;
2834
+
2835
+ export interface SponsoredPlacementFormatDeclaration {
2836
+ format_kind: 'sponsored_placement';
2837
+ params: CanonicalFormatSponsoredPlacementRetailMediaCatalogDriven;
2838
+ }
2839
+
2840
+ /**
2841
+ * Current task execution state. Indicates whether the task is completed, in progress (working), submitted for async processing, failed, or requires user input. REQUIRED on every task response envelope. Synchronous tasks (including read-only metadata calls like `get_adcp_capabilities`) MUST emit `status: "completed"`; async tasks emit `submitted`, `working`, `input-required`, etc. per their lifecycle. Agents MUST NOT emit the legacy task_status or response_status fields alongside this field — the status field is the single authoritative task state.
2842
+ */
2843
+ export type TaskStatus = 'submitted' | 'working' | 'input-required' | 'completed' | 'canceled' | 'failed' | 'rejected' | 'auth-required' | 'unknown';
2844
+
2845
+ /**
2846
+ * Transportation modes for isochrone-based catchment area calculations. Determines how travel time translates to geographic reach.
2847
+ */
2848
+ export type TransportMode = 'walking' | 'cycling' | 'driving' | 'public_transport';
2849
+
2850
+ /**
2851
+ * Type of user identifier. Used in audience sync, event logging, and TMP identity match requests to tell the receiver which identity graph to resolve against.
2852
+ */
2853
+ export type UIDType = 'rampid' | 'rampid_derived' | 'id5' | 'uid2' | 'euid' | 'pairid' | 'maid' | 'hashed_email' | 'publisher_first_party' | 'other';
2854
+
2855
+ export interface VASTVideoFormatDeclaration {
2856
+ format_kind: 'video_vast';
2857
+ params: CanonicalFormatVASTVideo;
2858
+ }
2859
+
2860
+ /**
2861
+ * Identifier for the metric within the vendor's vocabulary (e.g., `attention_units`, `gco2e_per_impression`, `demographic_reach`).
2862
+ */
2863
+ export type VendorMetricID = string;