@adcp/sdk 8.1.0-beta.7 → 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 (56) hide show
  1. package/README.md +12 -0
  2. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  3. package/dist/lib/types/activate-signal.d.ts +647 -0
  4. package/dist/lib/types/build-creative.d.ts +2105 -0
  5. package/dist/lib/types/calibrate-content.d.ts +675 -0
  6. package/dist/lib/types/check-governance.d.ts +619 -0
  7. package/dist/lib/types/comply-test-controller.d.ts +8428 -0
  8. package/dist/lib/types/create-collection-list.d.ts +693 -0
  9. package/dist/lib/types/create-content-standards.d.ts +830 -0
  10. package/dist/lib/types/create-media-buy.d.ts +3374 -0
  11. package/dist/lib/types/create-property-list.d.ts +836 -0
  12. package/dist/lib/types/delete-collection-list.d.ts +497 -0
  13. package/dist/lib/types/delete-property-list.d.ts +497 -0
  14. package/dist/lib/types/get-account-financials.d.ts +624 -0
  15. package/dist/lib/types/get-adcp-capabilities.d.ts +2863 -0
  16. package/dist/lib/types/get-collection-list.d.ts +763 -0
  17. package/dist/lib/types/get-content-standards.d.ts +919 -0
  18. package/dist/lib/types/get-creative-delivery.d.ts +2219 -0
  19. package/dist/lib/types/get-creative-features.d.ts +1736 -0
  20. package/dist/lib/types/get-media-buy-artifacts.d.ts +864 -0
  21. package/dist/lib/types/get-media-buys.d.ts +1670 -0
  22. package/dist/lib/types/get-plan-audit-logs.d.ts +455 -0
  23. package/dist/lib/types/get-products.d.ts +4935 -0
  24. package/dist/lib/types/get-property-list.d.ts +874 -0
  25. package/dist/lib/types/get-signals.d.ts +986 -0
  26. package/dist/lib/types/list-accounts.d.ts +851 -0
  27. package/dist/lib/types/list-content-standards.d.ts +975 -0
  28. package/dist/lib/types/list-creative-formats.d.ts +3132 -0
  29. package/dist/lib/types/list-creatives.d.ts +2390 -0
  30. package/dist/lib/types/list-property-lists.d.ts +855 -0
  31. package/dist/lib/types/log-event.d.ts +373 -0
  32. package/dist/lib/types/per-tool-index.json +391 -0
  33. package/dist/lib/types/preview-creative.d.ts +1981 -0
  34. package/dist/lib/types/provide-performance-feedback.d.ts +218 -0
  35. package/dist/lib/types/report-plan-outcome.d.ts +433 -0
  36. package/dist/lib/types/report-usage.d.ts +579 -0
  37. package/dist/lib/types/si-get-offering.d.ts +259 -0
  38. package/dist/lib/types/si-initiate-session.d.ts +372 -0
  39. package/dist/lib/types/si-send-message.d.ts +300 -0
  40. package/dist/lib/types/si-terminate-session.d.ts +213 -0
  41. package/dist/lib/types/sync-accounts.d.ts +856 -0
  42. package/dist/lib/types/sync-audiences.d.ts +707 -0
  43. package/dist/lib/types/sync-catalogs.d.ts +766 -0
  44. package/dist/lib/types/sync-creatives.d.ts +2134 -0
  45. package/dist/lib/types/sync-event-sources.d.ts +665 -0
  46. package/dist/lib/types/sync-governance.d.ts +558 -0
  47. package/dist/lib/types/sync-plans.d.ts +979 -0
  48. package/dist/lib/types/update-collection-list.d.ts +697 -0
  49. package/dist/lib/types/update-content-standards.d.ts +847 -0
  50. package/dist/lib/types/update-media-buy.d.ts +3047 -0
  51. package/dist/lib/types/update-property-list.d.ts +840 -0
  52. package/dist/lib/types/validate-content-delivery.d.ts +722 -0
  53. package/dist/lib/types/validate-input.d.ts +1683 -0
  54. package/dist/lib/version.d.ts +3 -3
  55. package/dist/lib/version.js +3 -3
  56. package/package.json +9 -2
@@ -0,0 +1,3132 @@
1
+ // AUTO-GENERATED — DO NOT EDIT.
2
+ // Per-tool .d.ts slice for `list_creative_formats`. 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 parameters for discovering supported creative formats
13
+ */
14
+ export interface ListCreativeFormatsRequest {
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
+ * Return only these specific format IDs (e.g., from get_products response)
25
+ */
26
+ format_ids?: FormatReferenceStructuredObject[];
27
+ /**
28
+ * Filter to formats that include these asset types. For third-party tags, search for 'html' or 'javascript'. E.g., ['image', 'text'] returns formats with images and text, ['javascript'] returns formats accepting JavaScript tags.
29
+ */
30
+ asset_types?: AssetContentType[];
31
+ /**
32
+ * Maximum width in pixels (inclusive). Returns formats where ANY render has width <= this value. For multi-render formats, matches if at least one render fits.
33
+ */
34
+ max_width?: number;
35
+ /**
36
+ * Maximum height in pixels (inclusive). Returns formats where ANY render has height <= this value. For multi-render formats, matches if at least one render fits.
37
+ */
38
+ max_height?: number;
39
+ /**
40
+ * Minimum width in pixels (inclusive). Returns formats where ANY render has width >= this value.
41
+ */
42
+ min_width?: number;
43
+ /**
44
+ * Minimum height in pixels (inclusive). Returns formats where ANY render has height >= this value.
45
+ */
46
+ min_height?: number;
47
+ /**
48
+ * Filter for responsive formats that adapt to container size. When true, returns formats without fixed dimensions.
49
+ */
50
+ is_responsive?: boolean;
51
+ /**
52
+ * Search for formats by name (case-insensitive partial match)
53
+ */
54
+ name_search?: string;
55
+ /**
56
+ * Filter to formats supported by the named publisher. Agents resolve via the three-tier order documented in `docs/creative/canonical-formats.mdx#format-discovery` (publisher's hosted adagents.json → AAO community mirror → agent-derived from own products' format_options). All fetches in the chain MUST follow the same transport contract as `format_schema` (https-only, SSRF guards, ≤5s timeout, 1 MiB cap, no redirects — see `static/schemas/source/core/product-format-declaration.json#format_schema`). Response carries `source: "publisher" | "aao_mirror" | "agent_derived"` so buyers know which tier produced the list. The pattern below is a syntactic floor — NOT an SSRF guard; agents MUST resolve the hostname and reject private/loopback/link-local/metadata IPs before fetching.
57
+ * @pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$
58
+ */
59
+ publisher_domain?: string;
60
+ property_id?: PropertyID;
61
+ wcag_level?: WCAGLevel;
62
+ /**
63
+ * Filter to formats that support all of these disclosure positions. When a format has disclosure_capabilities, match against those positions. Otherwise fall back to supported_disclosure_positions. Use to find formats compatible with a brief's compliance requirements.
64
+ */
65
+ disclosure_positions?: DisclosurePosition[];
66
+ /**
67
+ * Filter to formats where each requested persistence mode is supported by at least one position in disclosure_capabilities. Different positions may satisfy different modes. Use to find formats compatible with jurisdiction-specific persistence requirements (e.g., continuous for EU AI Act).
68
+ */
69
+ disclosure_persistence?: DisclosurePersistence[];
70
+ /**
71
+ * Filter to formats whose output_format_ids includes any of these format IDs. Returns formats that can produce these outputs — inspect each result's input_format_ids to see what inputs they accept.
72
+ */
73
+ output_format_ids?: FormatReferenceStructuredObject[];
74
+ /**
75
+ * Filter to formats whose input_format_ids includes any of these format IDs. Returns formats that accept these creatives as input — inspect each result's output_format_ids to see what they can produce.
76
+ */
77
+ input_format_ids?: FormatReferenceStructuredObject[];
78
+ pagination?: PaginationRequest;
79
+ context?: ContextObject;
80
+ ext?: ExtensionObject;
81
+ }
82
+
83
+ /**
84
+ * Response payload for list_creative_formats task
85
+ */
86
+ export interface ListCreativeFormatsResponse {
87
+ /**
88
+ * 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).
89
+ */
90
+ context_id?: string;
91
+ context?: ContextObject;
92
+ /**
93
+ * Unique identifier for tracking asynchronous operations. Present when a task requires extended processing time. Used to query task status and retrieve results when complete.
94
+ */
95
+ task_id?: string;
96
+ status: TaskStatus;
97
+ /**
98
+ * 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.
99
+ */
100
+ message?: string;
101
+ /**
102
+ * ISO 8601 timestamp when the response was generated. Useful for debugging, logging, cache validation, and tracking async operation progress.
103
+ */
104
+ timestamp?: string;
105
+ /**
106
+ * 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.
107
+ */
108
+ replayed?: boolean;
109
+ adcp_error?: Error;
110
+ push_notification_config?: PushNotificationConfig;
111
+ /**
112
+ * 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.
113
+ *
114
+ * 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.
115
+ *
116
+ * This is the primary correlation key for audit and reporting across the governance lifecycle.
117
+ */
118
+ governance_context?: string;
119
+ /**
120
+ * 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.
121
+ */
122
+ payload?: {};
123
+ /**
124
+ * 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.
125
+ */
126
+ adcp_version?: string;
127
+ /**
128
+ * 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.
129
+ */
130
+ adcp_major_version?: number;
131
+ /**
132
+ * Full format definitions for all formats this agent supports. Each format's authoritative source is indicated by its agent_url field.
133
+ */
134
+ formats: Format[];
135
+ /**
136
+ * Which tier of the resolution order produced this `formats[]` list when the request carried a `publisher_domain` filter. `publisher`: agent fetched `<publisher_domain>/.well-known/adagents.json` and returned its `formats[]` directly (publisher-authoritative). `aao_mirror`: publisher's hosted file was 404 / lacked `formats[]`, agent fell back to `https://creative.adcontextprotocol.org/translated/<platform>/adagents.json` (community-curated; lower authority — buyer SHOULD treat as advisory until platform adopts). `agent_derived`: neither tier 1 nor tier 2 returned a catalog, so the agent synthesized `formats[]` from the union of its own products' `format_options[]` for products selling the publisher's inventory (lowest authority — agent's view of what it sells, not the publisher's catalog). When two SDKs query the same agent for the same publisher and the agent-derived tier is in play, results may diverge by product set; buyers SHOULD record `source` for telemetry. When the request did NOT carry `publisher_domain`, this field MAY be omitted.
137
+ */
138
+ source?: 'publisher' | 'aao_mirror' | 'agent_derived';
139
+ /**
140
+ * Optional: Creative agents that provide additional formats. Buyers can recursively query these agents to discover more formats. No authentication required for list_creative_formats.
141
+ */
142
+ creative_agents?: {
143
+ /**
144
+ * Base URL for the creative agent (e.g., 'https://reference.adcp.org', 'https://dco.example.com'). Call list_creative_formats on this URL to get its formats.
145
+ */
146
+ agent_url: string;
147
+ /**
148
+ * Human-readable name for the creative agent
149
+ */
150
+ agent_name?: string;
151
+ /**
152
+ * Capabilities this creative agent provides
153
+ */
154
+ capabilities?: CreativeAgentCapability[];
155
+ }[];
156
+ /**
157
+ * Task-specific errors and warnings (e.g., format availability issues)
158
+ */
159
+ errors?: Error[];
160
+ pagination?: PaginationResponse;
161
+ /**
162
+ * When true, this response contains simulated data from sandbox mode.
163
+ */
164
+ sandbox?: boolean;
165
+ ext?: ExtensionObject;
166
+ }
167
+
168
+ export interface AgentPlacementFormatDeclaration {
169
+ format_kind: 'agent_placement';
170
+ params: CanonicalFormatAgentPlacementAISurfaceSponsoredPlacement;
171
+ }
172
+
173
+ /**
174
+ * Types of content that can be used as creative assets. Describes what KIND of content an asset contains (image, video, code, etc.), not where it displays.
175
+ */
176
+ export type AssetContentType = 'image' | 'video' | 'audio' | 'text' | 'markdown' | 'html' | 'css' | 'javascript' | 'vast' | 'daast' | 'url' | 'webhook' | 'brief' | 'catalog';
177
+
178
+ /**
179
+ * Requirements for audio creative assets.
180
+ */
181
+ export interface AudioAssetRequirements {
182
+ /**
183
+ * Minimum duration in milliseconds
184
+ * @minimum 1
185
+ */
186
+ min_duration_ms?: number;
187
+ /**
188
+ * Maximum duration in milliseconds
189
+ * @minimum 1
190
+ */
191
+ max_duration_ms?: number;
192
+ /**
193
+ * Accepted audio file formats
194
+ */
195
+ formats?: ('mp3' | 'aac' | 'wav' | 'ogg' | 'flac')[];
196
+ /**
197
+ * Maximum file size in kilobytes
198
+ * @minimum 1
199
+ */
200
+ max_file_size_kb?: number;
201
+ /**
202
+ * Accepted sample rates in Hz (e.g., [44100, 48000])
203
+ */
204
+ sample_rates?: number[];
205
+ /**
206
+ * Accepted audio channel configurations
207
+ */
208
+ channels?: ('mono' | 'stereo')[];
209
+ /**
210
+ * Minimum audio bitrate in kilobits per second
211
+ * @minimum 1
212
+ */
213
+ min_bitrate_kbps?: number;
214
+ /**
215
+ * Maximum audio bitrate in kilobits per second
216
+ * @minimum 1
217
+ */
218
+ max_bitrate_kbps?: number;
219
+ }
220
+
221
+ /**
222
+ * Audio channel configuration
223
+ */
224
+ export type AudioChannelLayout = 'mono' | 'stereo' | '5.1' | '7.1';
225
+
226
+ /**
227
+ * 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.
228
+ */
229
+ export type AuthenticationScheme = 'Bearer' | 'HMAC-SHA256';
230
+
231
+ /**
232
+ * Standard delivery and performance metrics available for reporting
233
+ */
234
+ export type AvailableMetric = 'impressions' | 'spend' | 'clicks' | 'ctr' | 'views' | 'completed_views' | 'completion_rate' | 'conversions' | 'conversion_value' | 'roas' | 'cost_per_acquisition' | 'new_to_brand_rate' | 'leads' | 'reach' | 'frequency' | 'grps' | 'engagements' | 'engagement_rate' | 'follows' | 'saves' | 'profile_visits' | 'viewability' | 'quartile_data' | 'dooh_metrics' | 'cost_per_click' | 'cost_per_completed_view' | 'cpm' | 'downloads' | 'units_sold' | 'new_to_brand_units' | 'plays' | 'incremental_sales_lift' | 'brand_lift' | 'foot_traffic' | 'conversion_lift' | 'brand_search_lift';
235
+
236
+ export interface BaseGroupAsset {
237
+ /**
238
+ * Identifier for this asset within the group
239
+ */
240
+ asset_id: string;
241
+ /**
242
+ * Descriptive label for this asset's purpose. For documentation and UI display only — manifests key assets by asset_id, not asset_role.
243
+ */
244
+ asset_role?: string;
245
+ /**
246
+ * Optional canonical asset_group_id this slot fills, drawn from /schemas/core/asset-group-vocabulary.json. Same semantics as on baseIndividualAsset — lets buyers and migration tools resolve v1 author-invented slot names to canonical names.
247
+ */
248
+ asset_group_id?: string;
249
+ /**
250
+ * Whether this asset is required within each repetition of the group
251
+ */
252
+ required: boolean;
253
+ /**
254
+ * Publisher-controlled elements rendered on top of buyer content at this asset's position (e.g., carousel navigation arrows, slide indicators). Creative agents should avoid placing critical content within overlay bounds.
255
+ */
256
+ overlays?: Overlay[];
257
+ }
258
+
259
+ export interface BaseIndividualAsset {
260
+ /**
261
+ * Discriminator indicating this is an individual asset
262
+ */
263
+ item_type: 'individual';
264
+ /**
265
+ * Unique identifier for this asset. Creative manifests MUST use this exact value as the key in the assets object.
266
+ */
267
+ asset_id: string;
268
+ /**
269
+ * Descriptive label for this asset's purpose (e.g., 'hero_image', 'logo', 'third_party_tracking'). For documentation and UI display only — manifests key assets by asset_id, not asset_role.
270
+ */
271
+ asset_role?: string;
272
+ /**
273
+ * Whether this asset is required (true) or optional (false). Required assets must be provided for a valid creative. Optional assets enhance the creative but are not mandatory.
274
+ */
275
+ required: boolean;
276
+ /**
277
+ * Publisher-controlled elements rendered on top of buyer content at this asset's position (e.g., video player controls, publisher logos). Creative agents should avoid placing critical content (CTAs, logos, key copy) within overlay bounds.
278
+ */
279
+ overlays?: Overlay[];
280
+ /**
281
+ * Optional canonical asset_group_id this slot fills, drawn from /schemas/core/asset-group-vocabulary.json. Lets buyers and migration tools resolve v1 author-invented slot names (e.g., `click_url`) to canonical names (e.g., `landing_page_url`). Validators MAY soft-warn when a v1 slot's asset_id is a known alias but no asset_group_id is declared.
282
+ */
283
+ asset_group_id?: string;
284
+ }
285
+
286
+ /**
287
+ * Requirements for CSS creative assets.
288
+ */
289
+ export interface CSSAssetRequirements {
290
+ /**
291
+ * Maximum file size in kilobytes
292
+ * @minimum 1
293
+ */
294
+ max_file_size_kb?: number;
295
+ }
296
+
297
+ /**
298
+ * **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.
299
+ *
300
+ * 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.
301
+ */
302
+ export interface CanonicalFormatAgentPlacementAISurfaceSponsoredPlacement {
303
+ /**
304
+ * 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.
305
+ */
306
+ experimental?: unknown;
307
+ /**
308
+ * 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.
309
+ */
310
+ deprecated?: boolean;
311
+ /**
312
+ * 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.
313
+ */
314
+ v1_translatable?: unknown;
315
+ /**
316
+ * 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.
317
+ */
318
+ since_version?: string;
319
+ /**
320
+ * 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').
321
+ */
322
+ migration_target_version?: string;
323
+ /**
324
+ * 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).
325
+ */
326
+ composition_model?: 'deterministic' | 'algorithmic';
327
+ /**
328
+ * 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.
329
+ */
330
+ provenance_required?: boolean;
331
+ /**
332
+ * 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.
333
+ *
334
+ * **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.
335
+ */
336
+ platform_extensions?: PlatformExtensionReference[];
337
+ /**
338
+ * 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.
339
+ *
340
+ * **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.
341
+ */
342
+ synthesis_nondeterministic?: boolean;
343
+ /**
344
+ * 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.
345
+ */
346
+ slots?: unknown;
347
+ /**
348
+ * 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).
349
+ */
350
+ production_window_business_days?: number;
351
+ /**
352
+ * How the surface presents the mention. `text` = inline text (chat, search snippet). `audio` = TTS-synthesized voice. `card` = structured card with optional image + text.
353
+ */
354
+ output_modality?: 'text' | 'audio' | 'card';
355
+ /**
356
+ * For text output: maximum length of the surface-composed mention text.
357
+ * @minimum 1
358
+ */
359
+ max_mention_length_chars?: number;
360
+ /**
361
+ * For audio output: maximum duration of the spoken mention in milliseconds.
362
+ * @minimum 1
363
+ */
364
+ max_mention_duration_ms?: number;
365
+ /**
366
+ * Whether the product accepts an offering reference (specific product/service to promote within the mention) in addition to brand context.
367
+ */
368
+ supports_offering_reference?: boolean;
369
+ /**
370
+ * Whether the surface attaches a landing page URL to the mention (citation, learn-more link).
371
+ */
372
+ supports_landing_page_url?: boolean;
373
+ /**
374
+ * **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.
375
+ */
376
+ tone_constraints?: string[];
377
+ /**
378
+ * Whether the surface must include an explicit sponsorship disclosure label.
379
+ */
380
+ disclosure_required?: boolean;
381
+ }
382
+
383
+ /**
384
+ * 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).
385
+ */
386
+ export interface CanonicalFormatDAASTAudio {
387
+ /**
388
+ * 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`).
389
+ *
390
+ * Three drivers of `experimental: true`:
391
+ * 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).
392
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
393
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
394
+ *
395
+ * 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).
396
+ */
397
+ experimental?: boolean;
398
+ /**
399
+ * 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.
400
+ */
401
+ deprecated?: boolean;
402
+ /**
403
+ * 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.
404
+ *
405
+ * 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`.
406
+ */
407
+ v1_translatable?: boolean;
408
+ /**
409
+ * 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.
410
+ */
411
+ since_version?: string;
412
+ /**
413
+ * 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').
414
+ */
415
+ migration_target_version?: string;
416
+ /**
417
+ * 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).
418
+ */
419
+ composition_model?: 'deterministic' | 'algorithmic';
420
+ /**
421
+ * 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.
422
+ */
423
+ provenance_required?: boolean;
424
+ /**
425
+ * 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.
426
+ *
427
+ * **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.
428
+ */
429
+ platform_extensions?: PlatformExtensionReference[];
430
+ /**
431
+ * 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.
432
+ *
433
+ * **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.
434
+ */
435
+ synthesis_nondeterministic?: boolean;
436
+ /**
437
+ * 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.
438
+ */
439
+ slots?: unknown;
440
+ /**
441
+ * 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).
442
+ */
443
+ production_window_business_days?: number;
444
+ daast_version?: '1.0' | '1.1';
445
+ /**
446
+ * [min, max] duration in milliseconds. **Precedence**: `duration_ms_exact` takes precedence when both ship. SDKs SHOULD lint a warning when both fields ship.
447
+ */
448
+ duration_ms_range?: number[];
449
+ /**
450
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship.
451
+ * @minimum 1
452
+ */
453
+ duration_ms_exact?: number;
454
+ linear_required?: boolean;
455
+ /**
456
+ * @minimum 0
457
+ */
458
+ max_wrapper_depth?: number;
459
+ ssl_required?: boolean;
460
+ companion_image_required?: boolean;
461
+ }
462
+
463
+ /**
464
+ * 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).
465
+ */
466
+ export type CanonicalFormatDisplayTag = SizeModeMutex & {
467
+ /**
468
+ * 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`).
469
+ *
470
+ * Three drivers of `experimental: true`:
471
+ * 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).
472
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
473
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
474
+ *
475
+ * 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).
476
+ */
477
+ experimental?: boolean;
478
+ /**
479
+ * 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.
480
+ */
481
+ deprecated?: boolean;
482
+ /**
483
+ * 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.
484
+ *
485
+ * 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`.
486
+ */
487
+ v1_translatable?: boolean;
488
+ /**
489
+ * 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.
490
+ */
491
+ since_version?: string;
492
+ /**
493
+ * 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').
494
+ */
495
+ migration_target_version?: string;
496
+ /**
497
+ * 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).
498
+ */
499
+ composition_model?: 'deterministic' | 'algorithmic';
500
+ /**
501
+ * 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.
502
+ */
503
+ provenance_required?: boolean;
504
+ /**
505
+ * 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.
506
+ *
507
+ * **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.
508
+ */
509
+ platform_extensions?: PlatformExtensionReference[];
510
+ /**
511
+ * 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.
512
+ *
513
+ * **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.
514
+ */
515
+ synthesis_nondeterministic?: boolean;
516
+ /**
517
+ * 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`.
518
+ */
519
+ slots?: unknown;
520
+ /**
521
+ * 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).
522
+ */
523
+ production_window_business_days?: number;
524
+ /**
525
+ * 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.
526
+ * @minimum 1
527
+ */
528
+ width?: number;
529
+ /**
530
+ * Required tag rendering height in pixels. See `width` for size-mode mutual exclusion.
531
+ * @minimum 1
532
+ */
533
+ height?: number;
534
+ /**
535
+ * 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.
536
+ */
537
+ sizes?: {
538
+ /**
539
+ * @minimum 1
540
+ */
541
+ width: number;
542
+ /**
543
+ * @minimum 1
544
+ */
545
+ height: number;
546
+ }[];
547
+ /**
548
+ * Minimum accepted width for responsive third-party tags. Pair with `max_width`. Mutually exclusive with `(width, height)` and `sizes[]`.
549
+ * @minimum 1
550
+ */
551
+ min_width?: number;
552
+ /**
553
+ * Maximum accepted width for responsive third-party tags. Pair with `min_width`.
554
+ * @minimum 1
555
+ */
556
+ max_width?: number;
557
+ /**
558
+ * Minimum accepted height for responsive third-party tags. Pair with `max_height`.
559
+ * @minimum 1
560
+ */
561
+ min_height?: number;
562
+ /**
563
+ * Maximum accepted height for responsive third-party tags. Pair with `min_height`.
564
+ * @minimum 1
565
+ */
566
+ max_height?: number;
567
+ /**
568
+ * Tag delivery mechanisms accepted.
569
+ */
570
+ supported_tag_types?: ('iframe' | 'javascript' | '1x1_redirect')[];
571
+ /**
572
+ * Whether the tag URL must be HTTPS.
573
+ */
574
+ ssl_required?: boolean;
575
+ /**
576
+ * Maximum redirect chain depth permitted.
577
+ * @minimum 0
578
+ */
579
+ max_redirect_depth?: number;
580
+ /**
581
+ * Maximum tag-server response time in milliseconds.
582
+ * @minimum 1
583
+ */
584
+ max_response_time_ms?: number;
585
+ /**
586
+ * Whether a backup image must accompany the tag for environments that cannot render the third-party tag.
587
+ */
588
+ backup_image_required?: boolean;
589
+ /**
590
+ * @minimum 1
591
+ */
592
+ backup_image_max_size_kb?: number;
593
+ /**
594
+ * Whether the buyer's tag must integrate IAB Open Measurement SDK for viewability.
595
+ */
596
+ om_sdk_required?: boolean;
597
+ };
598
+
599
+ /**
600
+ * 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.
601
+ */
602
+ export type CanonicalFormatHTML5Banner = SizeModeMutex & {
603
+ /**
604
+ * 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`).
605
+ *
606
+ * Three drivers of `experimental: true`:
607
+ * 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).
608
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
609
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
610
+ *
611
+ * 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).
612
+ */
613
+ experimental?: boolean;
614
+ /**
615
+ * 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.
616
+ */
617
+ deprecated?: boolean;
618
+ /**
619
+ * 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.
620
+ *
621
+ * 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`.
622
+ */
623
+ v1_translatable?: boolean;
624
+ /**
625
+ * 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.
626
+ */
627
+ since_version?: string;
628
+ /**
629
+ * 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').
630
+ */
631
+ migration_target_version?: string;
632
+ /**
633
+ * 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).
634
+ */
635
+ composition_model?: 'deterministic' | 'algorithmic';
636
+ /**
637
+ * 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.
638
+ */
639
+ provenance_required?: boolean;
640
+ /**
641
+ * 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.
642
+ *
643
+ * **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.
644
+ */
645
+ platform_extensions?: PlatformExtensionReference[];
646
+ /**
647
+ * 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.
648
+ *
649
+ * **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.
650
+ */
651
+ synthesis_nondeterministic?: boolean;
652
+ /**
653
+ * 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.
654
+ */
655
+ slots?: unknown;
656
+ /**
657
+ * 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).
658
+ */
659
+ production_window_business_days?: number;
660
+ /**
661
+ * 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.
662
+ * @minimum 1
663
+ */
664
+ width?: number;
665
+ /**
666
+ * Required banner height in pixels. See `width` for size-mode mutual exclusion.
667
+ * @minimum 1
668
+ */
669
+ height?: number;
670
+ /**
671
+ * 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.
672
+ */
673
+ sizes?: {
674
+ /**
675
+ * @minimum 1
676
+ */
677
+ width: number;
678
+ /**
679
+ * @minimum 1
680
+ */
681
+ height: number;
682
+ }[];
683
+ /**
684
+ * Minimum accepted width for responsive HTML5 banners that adapt within a range. Pair with `max_width`. Mutually exclusive with `(width, height)` and `sizes[]`.
685
+ * @minimum 1
686
+ */
687
+ min_width?: number;
688
+ /**
689
+ * Maximum accepted width for responsive HTML5 banners. Pair with `min_width`.
690
+ * @minimum 1
691
+ */
692
+ max_width?: number;
693
+ /**
694
+ * Minimum accepted height for responsive HTML5 banners. Pair with `max_height`.
695
+ * @minimum 1
696
+ */
697
+ min_height?: number;
698
+ /**
699
+ * Maximum accepted height for responsive HTML5 banners. Pair with `min_height`.
700
+ * @minimum 1
701
+ */
702
+ max_height?: number;
703
+ /**
704
+ * Maximum initial-load file size (zip + above-the-fold assets) in kilobytes. IAB display standards: 200 KB for fixed sizes, 100 KB for mobile.
705
+ * @minimum 1
706
+ */
707
+ max_initial_load_kb?: number;
708
+ /**
709
+ * Maximum polite-load file size after host-initiated subload, in kilobytes. IAB display standards: 500 KB for fixed sizes.
710
+ * @minimum 1
711
+ */
712
+ max_polite_load_kb?: number;
713
+ /**
714
+ * Whether the host page must initiate the polite-load phase. IAB-compliant banners require true.
715
+ */
716
+ host_initiated_subload?: boolean;
717
+ /**
718
+ * Maximum total animation duration in milliseconds. IAB standard: 30000 (30 seconds).
719
+ * @minimum 0
720
+ */
721
+ max_animation_duration_ms?: number;
722
+ /**
723
+ * Maximum CPU load percentage during render.
724
+ * @minimum 1
725
+ * @maximum 100
726
+ */
727
+ max_cpu_load_percent?: number;
728
+ /**
729
+ * Whether MRAID compatibility is required (mobile in-app).
730
+ */
731
+ mraid_required?: boolean;
732
+ /**
733
+ * Required MRAID version when mraid_required is true.
734
+ */
735
+ mraid_version?: '2.0' | '3.0';
736
+ /**
737
+ * Whether IAB Open Measurement SDK integration is required.
738
+ */
739
+ om_sdk_required?: boolean;
740
+ /**
741
+ * Name of the click-tag macro the bundle must use.
742
+ */
743
+ clicktag_macro?: 'clickTag' | 'clickTAG';
744
+ /**
745
+ * Whether a backup image must accompany the zip for non-HTML5 environments.
746
+ */
747
+ backup_image_required?: boolean;
748
+ /**
749
+ * Maximum backup image file size in kilobytes.
750
+ * @minimum 1
751
+ */
752
+ backup_image_max_size_kb?: number;
753
+ ssl_required?: boolean;
754
+ };
755
+
756
+ /**
757
+ * 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`.
758
+ */
759
+ export interface CanonicalFormatHostedAudio {
760
+ /**
761
+ * 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`).
762
+ *
763
+ * Three drivers of `experimental: true`:
764
+ * 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).
765
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
766
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
767
+ *
768
+ * 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).
769
+ */
770
+ experimental?: boolean;
771
+ /**
772
+ * 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.
773
+ */
774
+ deprecated?: boolean;
775
+ /**
776
+ * 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.
777
+ *
778
+ * 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`.
779
+ */
780
+ v1_translatable?: boolean;
781
+ /**
782
+ * 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.
783
+ */
784
+ since_version?: string;
785
+ /**
786
+ * 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').
787
+ */
788
+ migration_target_version?: string;
789
+ /**
790
+ * 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).
791
+ */
792
+ composition_model?: 'deterministic' | 'algorithmic';
793
+ /**
794
+ * 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.
795
+ */
796
+ provenance_required?: boolean;
797
+ /**
798
+ * 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.
799
+ *
800
+ * **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.
801
+ */
802
+ platform_extensions?: PlatformExtensionReference[];
803
+ /**
804
+ * 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.
805
+ *
806
+ * **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.
807
+ */
808
+ synthesis_nondeterministic?: boolean;
809
+ /**
810
+ * 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'`.
811
+ */
812
+ slots?: unknown;
813
+ /**
814
+ * 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).
815
+ */
816
+ production_window_business_days?: number;
817
+ /**
818
+ * [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.
819
+ */
820
+ duration_ms_range?: number[];
821
+ /**
822
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship.
823
+ * @minimum 1
824
+ */
825
+ duration_ms_exact?: number;
826
+ audio_codecs?: ('mp3' | 'aac' | 'wav' | 'opus' | 'flac')[];
827
+ audio_sample_rates?: number[];
828
+ audio_channels?: ('mono' | 'stereo')[];
829
+ /**
830
+ * @minimum 1
831
+ */
832
+ min_bitrate_kbps?: number;
833
+ /**
834
+ * @minimum 1
835
+ */
836
+ max_bitrate_kbps?: number;
837
+ /**
838
+ * Required integrated loudness in LUFS (typical: -16 for streaming/podcast, -23 for broadcast). Negative values.
839
+ */
840
+ loudness_lufs?: number;
841
+ /**
842
+ * Permitted deviation from loudness_lufs in dB.
843
+ * @minimum 0
844
+ */
845
+ loudness_tolerance_db?: number;
846
+ /**
847
+ * Maximum true-peak level in dBFS (typical: -2).
848
+ */
849
+ true_peak_dbfs?: number;
850
+ /**
851
+ * 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.
852
+ */
853
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
854
+ /**
855
+ * 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`).
856
+ */
857
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
858
+ companion_image_required?: boolean;
859
+ companion_image_aspect_ratio?: string;
860
+ /**
861
+ * @minimum 1
862
+ */
863
+ companion_image_max_file_size_kb?: number;
864
+ /**
865
+ * @minimum 1
866
+ */
867
+ brand_name_max_chars?: number;
868
+ }
869
+
870
+ /**
871
+ * 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.
872
+ */
873
+ export interface CanonicalFormatHostedVideo {
874
+ /**
875
+ * 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`).
876
+ *
877
+ * Three drivers of `experimental: true`:
878
+ * 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).
879
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
880
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
881
+ *
882
+ * 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).
883
+ */
884
+ experimental?: boolean;
885
+ /**
886
+ * 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.
887
+ */
888
+ deprecated?: boolean;
889
+ /**
890
+ * 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.
891
+ *
892
+ * 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`.
893
+ */
894
+ v1_translatable?: boolean;
895
+ /**
896
+ * 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.
897
+ */
898
+ since_version?: string;
899
+ /**
900
+ * 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').
901
+ */
902
+ migration_target_version?: string;
903
+ /**
904
+ * 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).
905
+ */
906
+ composition_model?: 'deterministic' | 'algorithmic';
907
+ /**
908
+ * 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.
909
+ */
910
+ provenance_required?: boolean;
911
+ /**
912
+ * 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.
913
+ *
914
+ * **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.
915
+ */
916
+ platform_extensions?: PlatformExtensionReference[];
917
+ /**
918
+ * 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.
919
+ *
920
+ * **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.
921
+ */
922
+ synthesis_nondeterministic?: boolean;
923
+ /**
924
+ * 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.
925
+ */
926
+ slots?: unknown;
927
+ /**
928
+ * 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).
929
+ */
930
+ production_window_business_days?: number;
931
+ /**
932
+ * Video orientation. Vertical = 9:16 (Reels, Stories, Shorts). Horizontal = 16:9 (instream, CTV). Square = 1:1 (in-feed).
933
+ */
934
+ orientation?: 'vertical' | 'horizontal' | 'square';
935
+ /**
936
+ * Aspect ratio. Inferred from orientation if omitted.
937
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
938
+ */
939
+ aspect_ratio?: string;
940
+ /**
941
+ * @minimum 1
942
+ */
943
+ min_width?: number;
944
+ /**
945
+ * @minimum 1
946
+ */
947
+ min_height?: number;
948
+ /**
949
+ * @minimum 1
950
+ */
951
+ max_width?: number;
952
+ /**
953
+ * @minimum 1
954
+ */
955
+ max_height?: number;
956
+ /**
957
+ * [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.
958
+ */
959
+ duration_ms_range?: number[];
960
+ /**
961
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship (see `duration_ms_range` description).
962
+ * @minimum 1
963
+ */
964
+ duration_ms_exact?: number;
965
+ video_codecs?: ('h264' | 'h265' | 'vp8' | 'vp9' | 'av1' | 'prores')[];
966
+ audio_codecs?: ('aac' | 'mp3' | 'opus' | 'pcm')[];
967
+ containers?: ('mp4' | 'webm' | 'mov')[];
968
+ /**
969
+ * @minimum 1
970
+ */
971
+ min_bitrate_kbps?: number;
972
+ /**
973
+ * @minimum 1
974
+ */
975
+ max_bitrate_kbps?: number;
976
+ /**
977
+ * @minimum 1
978
+ */
979
+ max_file_size_mb?: number;
980
+ frame_rates?: number[];
981
+ captions?: 'required' | 'recommended' | 'not_required';
982
+ om_sdk_required?: boolean;
983
+ /**
984
+ * @minimum 1
985
+ */
986
+ headline_max_chars?: number;
987
+ /**
988
+ * @minimum 1
989
+ */
990
+ primary_text_max_chars?: number;
991
+ /**
992
+ * @minimum 1
993
+ */
994
+ brand_name_max_chars?: number;
995
+ cta_values?: string[];
996
+ /**
997
+ * Permitted companion banner widths (instream video).
998
+ */
999
+ companion_banner_widths?: number[];
1000
+ companion_banner_heights?: number[];
1001
+ /**
1002
+ * 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.
1003
+ */
1004
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1005
+ /**
1006
+ * 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.
1007
+ */
1008
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
1009
+ }
1010
+
1011
+ /**
1012
+ * 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.
1013
+ */
1014
+ export type CanonicalFormatImage = SizeModeMutex & {
1015
+ /**
1016
+ * 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`).
1017
+ *
1018
+ * Three drivers of `experimental: true`:
1019
+ * 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).
1020
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1021
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1022
+ *
1023
+ * 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).
1024
+ */
1025
+ experimental?: boolean;
1026
+ /**
1027
+ * 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.
1028
+ */
1029
+ deprecated?: boolean;
1030
+ /**
1031
+ * 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.
1032
+ *
1033
+ * 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`.
1034
+ */
1035
+ v1_translatable?: boolean;
1036
+ /**
1037
+ * 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.
1038
+ */
1039
+ since_version?: string;
1040
+ /**
1041
+ * 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').
1042
+ */
1043
+ migration_target_version?: string;
1044
+ /**
1045
+ * 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).
1046
+ */
1047
+ composition_model?: 'deterministic' | 'algorithmic';
1048
+ /**
1049
+ * 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.
1050
+ */
1051
+ provenance_required?: boolean;
1052
+ /**
1053
+ * 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.
1054
+ *
1055
+ * **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.
1056
+ */
1057
+ platform_extensions?: PlatformExtensionReference[];
1058
+ /**
1059
+ * 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.
1060
+ *
1061
+ * **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.
1062
+ */
1063
+ synthesis_nondeterministic?: boolean;
1064
+ /**
1065
+ * 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.
1066
+ */
1067
+ slots?: unknown;
1068
+ /**
1069
+ * 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).
1070
+ */
1071
+ production_window_business_days?: number;
1072
+ /**
1073
+ * 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.
1074
+ * @minimum 1
1075
+ */
1076
+ width?: number;
1077
+ /**
1078
+ * Required image height in pixels. See `width` for size-mode mutual exclusion.
1079
+ * @minimum 1
1080
+ */
1081
+ height?: number;
1082
+ /**
1083
+ * 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.
1084
+ */
1085
+ sizes?: {
1086
+ /**
1087
+ * @minimum 1
1088
+ */
1089
+ width: number;
1090
+ /**
1091
+ * @minimum 1
1092
+ */
1093
+ height: number;
1094
+ }[];
1095
+ /**
1096
+ * 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[]`.
1097
+ * @minimum 1
1098
+ */
1099
+ min_width?: number;
1100
+ /**
1101
+ * Maximum accepted width in pixels for responsive slots. Pair with `min_width`. See `min_width` for size-mode mutual exclusion.
1102
+ * @minimum 1
1103
+ */
1104
+ max_width?: number;
1105
+ /**
1106
+ * Minimum accepted height in pixels for responsive slots. Pair with `max_height`.
1107
+ * @minimum 1
1108
+ */
1109
+ min_height?: number;
1110
+ /**
1111
+ * Maximum accepted height in pixels for responsive slots. Pair with `min_height`.
1112
+ * @minimum 1
1113
+ */
1114
+ max_height?: number;
1115
+ /**
1116
+ * 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.
1117
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
1118
+ */
1119
+ aspect_ratio?: string;
1120
+ /**
1121
+ * Maximum file size in kilobytes.
1122
+ * @minimum 1
1123
+ */
1124
+ max_file_size_kb?: number;
1125
+ /**
1126
+ * Permitted image file formats.
1127
+ */
1128
+ image_formats?: ('jpg' | 'jpeg' | 'png' | 'gif' | 'webp' | 'svg')[];
1129
+ /**
1130
+ * Whether the image and its trackers must be served over HTTPS.
1131
+ */
1132
+ ssl_required?: boolean;
1133
+ /**
1134
+ * @minimum 1
1135
+ */
1136
+ headline_max_chars?: number;
1137
+ /**
1138
+ * @minimum 1
1139
+ */
1140
+ body_text_max_chars?: number;
1141
+ /**
1142
+ * Permitted CTA values for this product (e.g., ['LEARN_MORE', 'SHOP_NOW']).
1143
+ */
1144
+ cta_values?: string[];
1145
+ /**
1146
+ * 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).
1147
+ *
1148
+ * 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.
1149
+ */
1150
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1151
+ /**
1152
+ * 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`).
1153
+ */
1154
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
1155
+ };
1156
+
1157
+ /**
1158
+ * 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`.
1159
+ *
1160
+ * 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.
1161
+ */
1162
+ export interface CanonicalFormatImageCarousel {
1163
+ /**
1164
+ * 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`).
1165
+ *
1166
+ * Three drivers of `experimental: true`:
1167
+ * 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).
1168
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1169
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1170
+ *
1171
+ * 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).
1172
+ */
1173
+ experimental?: boolean;
1174
+ /**
1175
+ * 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.
1176
+ */
1177
+ deprecated?: boolean;
1178
+ /**
1179
+ * 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.
1180
+ */
1181
+ v1_translatable?: unknown;
1182
+ /**
1183
+ * 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.
1184
+ */
1185
+ since_version?: string;
1186
+ /**
1187
+ * 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').
1188
+ */
1189
+ migration_target_version?: string;
1190
+ /**
1191
+ * 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).
1192
+ */
1193
+ composition_model?: 'deterministic' | 'algorithmic';
1194
+ /**
1195
+ * 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.
1196
+ */
1197
+ provenance_required?: boolean;
1198
+ /**
1199
+ * 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.
1200
+ *
1201
+ * **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.
1202
+ */
1203
+ platform_extensions?: PlatformExtensionReference[];
1204
+ /**
1205
+ * 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.
1206
+ *
1207
+ * **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.
1208
+ */
1209
+ synthesis_nondeterministic?: boolean;
1210
+ /**
1211
+ * 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.
1212
+ */
1213
+ slots?: unknown;
1214
+ /**
1215
+ * 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).
1216
+ */
1217
+ production_window_business_days?: number;
1218
+ /**
1219
+ * Aspect ratio shared across all cards (e.g., '1:1', '1.91:1', '4:5').
1220
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
1221
+ */
1222
+ card_aspect_ratio?: string;
1223
+ /**
1224
+ * Minimum card count (typical: 2 or 3).
1225
+ * @minimum 2
1226
+ */
1227
+ min_cards?: number;
1228
+ /**
1229
+ * Maximum card count (typical: 6, 10, or 35 depending on platform).
1230
+ */
1231
+ max_cards?: number;
1232
+ /**
1233
+ * 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").
1234
+ */
1235
+ allowed_card_media_asset_types?: ('image' | 'video')[];
1236
+ /**
1237
+ * DEPRECATED — alias for `allowed_card_media_asset_types`. Kept for back-compat; prefer the new field name. Removed in 5.0.
1238
+ */
1239
+ allowed_card_asset_types?: ('image' | 'video')[];
1240
+ /**
1241
+ * @minimum 1
1242
+ */
1243
+ card_image_max_file_size_kb?: number;
1244
+ /**
1245
+ * @minimum 1
1246
+ */
1247
+ card_video_max_duration_ms?: number;
1248
+ /**
1249
+ * Maximum length of the carousel-level primary text.
1250
+ * @minimum 1
1251
+ */
1252
+ primary_text_max_chars?: number;
1253
+ /**
1254
+ * Per-card headline character limit. Governs the `headline` field on each card-asset in the `cards` slot.
1255
+ * @minimum 1
1256
+ */
1257
+ card_headline_max_chars?: number;
1258
+ /**
1259
+ * 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).
1260
+ * @minimum 1
1261
+ */
1262
+ card_description_max_chars?: number;
1263
+ ssl_required?: boolean;
1264
+ }
1265
+
1266
+ /**
1267
+ * The v2 canonical-format-kind this v1 format projects to (`image`, `html5`, `display_tag`, `image_carousel`, `video_hosted`, `video_vast`, `audio_hosted`, `audio_daast`, `sponsored_placement`, `responsive_creative`, `agent_placement`, or `custom`).
1268
+ */
1269
+ export type CanonicalFormatKind = 'image' | 'html5' | 'display_tag' | 'image_carousel' | 'video_hosted' | 'video_vast' | 'audio_hosted' | 'audio_daast' | 'sponsored_placement' | 'native_in_feed' | 'responsive_creative' | 'agent_placement' | 'custom';
1270
+
1271
+ /**
1272
+ * 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.
1273
+ *
1274
+ * **Scope (normative — buyer-agent routing).** This canonical is the home for:
1275
+ * - IAB OpenRTB Native 1.2 in-feed native ads (publisher feeds, app feeds)
1276
+ * - Content-recommendation widgets (Taboola, Outbrain, Yahoo Recommendations)
1277
+ * - AdMob Native / Yahoo Native publisher slots
1278
+ * - In-feed sponsored placements without catalog dependency
1279
+ *
1280
+ * **Not this canonical:**
1281
+ * - Catalog-driven retail-media (Amazon SP, Criteo SP, CitrusAd SP) — use `sponsored_placement` (requires `source_catalog`).
1282
+ * - Algorithmic surface that picks from a buyer-supplied asset pool (Google PMax, Meta Advantage+) — use `responsive_creative`.
1283
+ * - Multi-card carousel — use `image_carousel`.
1284
+ * - Video-first native units where the asset is a hosted video file — use `video_hosted` with `applies_to_channels: ["native"]`.
1285
+ *
1286
+ * 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.
1287
+ */
1288
+ export interface CanonicalFormatNativeInFeed {
1289
+ /**
1290
+ * 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.
1291
+ */
1292
+ experimental?: unknown;
1293
+ /**
1294
+ * 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.
1295
+ */
1296
+ deprecated?: boolean;
1297
+ /**
1298
+ * 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.
1299
+ */
1300
+ v1_translatable?: unknown;
1301
+ /**
1302
+ * 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.
1303
+ */
1304
+ since_version?: string;
1305
+ /**
1306
+ * 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').
1307
+ */
1308
+ migration_target_version?: string;
1309
+ /**
1310
+ * 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).
1311
+ */
1312
+ composition_model?: 'deterministic' | 'algorithmic';
1313
+ /**
1314
+ * 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.
1315
+ */
1316
+ provenance_required?: boolean;
1317
+ /**
1318
+ * 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.
1319
+ *
1320
+ * **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.
1321
+ */
1322
+ platform_extensions?: PlatformExtensionReference[];
1323
+ /**
1324
+ * 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.
1325
+ *
1326
+ * **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.
1327
+ */
1328
+ synthesis_nondeterministic?: boolean;
1329
+ /**
1330
+ * 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).
1331
+ */
1332
+ slots?: unknown;
1333
+ /**
1334
+ * 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).
1335
+ */
1336
+ production_window_business_days?: number;
1337
+ /**
1338
+ * 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.
1339
+ * @minimum 1
1340
+ */
1341
+ title_max_chars?: number;
1342
+ /**
1343
+ * Maximum character length for the body_text slot. IAB native typical: 90 (mainline) to 140 (extended).
1344
+ * @minimum 1
1345
+ */
1346
+ body_text_max_chars?: number;
1347
+ /**
1348
+ * Maximum character length for the cta slot. Typical: 15–25.
1349
+ * @minimum 1
1350
+ */
1351
+ cta_max_chars?: number;
1352
+ /**
1353
+ * 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.
1354
+ */
1355
+ cta_values?: string[];
1356
+ /**
1357
+ * 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).
1358
+ */
1359
+ main_image_sizes?: {
1360
+ /**
1361
+ * @minimum 1
1362
+ */
1363
+ width: number;
1364
+ /**
1365
+ * @minimum 1
1366
+ */
1367
+ height: number;
1368
+ }[];
1369
+ /**
1370
+ * Required (width, height) for the icon slot when present (typical: 80×80 or 100×100).
1371
+ */
1372
+ icon_size?: {
1373
+ /**
1374
+ * @minimum 1
1375
+ */
1376
+ width: number;
1377
+ /**
1378
+ * @minimum 1
1379
+ */
1380
+ height: number;
1381
+ };
1382
+ /**
1383
+ * Maximum file size in kilobytes for main_image and icon.
1384
+ * @minimum 1
1385
+ */
1386
+ max_image_file_size_kb?: number;
1387
+ /**
1388
+ * Permitted image file formats.
1389
+ */
1390
+ image_formats?: ('jpg' | 'jpeg' | 'png' | 'gif' | 'webp')[];
1391
+ /**
1392
+ * Whether trackers, landing pages, and image URLs must be served over HTTPS.
1393
+ */
1394
+ ssl_required?: boolean;
1395
+ /**
1396
+ * 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.
1397
+ */
1398
+ asset_source?: 'buyer_uploaded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1399
+ /**
1400
+ * 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.
1401
+ */
1402
+ buyer_asset_acceptance?: 'accepted' | 'rejected';
1403
+ }
1404
+
1405
+ /**
1406
+ * 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.).
1407
+ */
1408
+ export interface CanonicalFormatResponsiveCreative {
1409
+ /**
1410
+ * 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).
1411
+ */
1412
+ experimental?: unknown;
1413
+ /**
1414
+ * 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.
1415
+ */
1416
+ deprecated?: boolean;
1417
+ /**
1418
+ * 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.
1419
+ */
1420
+ v1_translatable?: unknown;
1421
+ /**
1422
+ * 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.
1423
+ */
1424
+ since_version?: string;
1425
+ /**
1426
+ * 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').
1427
+ */
1428
+ migration_target_version?: string;
1429
+ /**
1430
+ * 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).
1431
+ */
1432
+ composition_model?: 'deterministic' | 'algorithmic';
1433
+ /**
1434
+ * 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.
1435
+ */
1436
+ provenance_required?: boolean;
1437
+ /**
1438
+ * 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.
1439
+ *
1440
+ * **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.
1441
+ */
1442
+ platform_extensions?: PlatformExtensionReference[];
1443
+ /**
1444
+ * 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.
1445
+ *
1446
+ * **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.
1447
+ */
1448
+ synthesis_nondeterministic?: boolean;
1449
+ slots?: unknown;
1450
+ /**
1451
+ * 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).
1452
+ */
1453
+ production_window_business_days?: number;
1454
+ /**
1455
+ * @minimum 0
1456
+ */
1457
+ headlines_min?: number;
1458
+ /**
1459
+ * @minimum 0
1460
+ */
1461
+ headlines_max?: number;
1462
+ /**
1463
+ * @minimum 1
1464
+ */
1465
+ headline_max_chars?: number;
1466
+ /**
1467
+ * @minimum 0
1468
+ */
1469
+ long_headlines_min?: number;
1470
+ /**
1471
+ * @minimum 0
1472
+ */
1473
+ long_headlines_max?: number;
1474
+ /**
1475
+ * @minimum 1
1476
+ */
1477
+ long_headline_max_chars?: number;
1478
+ /**
1479
+ * @minimum 0
1480
+ */
1481
+ descriptions_min?: number;
1482
+ /**
1483
+ * @minimum 0
1484
+ */
1485
+ descriptions_max?: number;
1486
+ /**
1487
+ * @minimum 1
1488
+ */
1489
+ description_max_chars?: number;
1490
+ /**
1491
+ * @minimum 0
1492
+ */
1493
+ images_landscape_min?: number;
1494
+ /**
1495
+ * @minimum 0
1496
+ */
1497
+ images_landscape_max?: number;
1498
+ images_landscape_aspect_ratio?: string;
1499
+ /**
1500
+ * @minimum 0
1501
+ */
1502
+ images_square_min?: number;
1503
+ /**
1504
+ * @minimum 0
1505
+ */
1506
+ images_square_max?: number;
1507
+ /**
1508
+ * @minimum 0
1509
+ */
1510
+ images_vertical_min?: number;
1511
+ /**
1512
+ * @minimum 0
1513
+ */
1514
+ images_vertical_max?: number;
1515
+ /**
1516
+ * @minimum 0
1517
+ */
1518
+ videos_min?: number;
1519
+ /**
1520
+ * @minimum 0
1521
+ */
1522
+ videos_max?: number;
1523
+ /**
1524
+ * @minimum 1
1525
+ */
1526
+ video_min_duration_ms?: number;
1527
+ /**
1528
+ * @minimum 1
1529
+ */
1530
+ video_max_duration_ms?: number;
1531
+ /**
1532
+ * @minimum 0
1533
+ */
1534
+ logo_min?: number;
1535
+ /**
1536
+ * @minimum 0
1537
+ */
1538
+ logo_max?: number;
1539
+ logo_aspect_ratios?: string[];
1540
+ /**
1541
+ * @minimum 1
1542
+ */
1543
+ business_name_max_chars?: number;
1544
+ /**
1545
+ * @minimum 1
1546
+ */
1547
+ asset_image_max_file_size_kb?: number;
1548
+ /**
1549
+ * Whether the product can additionally consume a catalog reference (e.g., PMax with product feed).
1550
+ */
1551
+ supports_catalog_input?: boolean;
1552
+ }
1553
+
1554
+ /**
1555
+ * 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).
1556
+ *
1557
+ * **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.
1558
+ *
1559
+ * **Not this canonical (route elsewhere):**
1560
+ * - 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).
1561
+ * - Algorithmic surface that picks from a buyer-supplied asset pool (Google PMax, Meta Advantage+) — use `responsive_creative`.
1562
+ * - Single-image or single-video creative — use `image` or `video_hosted`.
1563
+ *
1564
+ * 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).
1565
+ */
1566
+ export interface CanonicalFormatSponsoredPlacementRetailMediaCatalogDriven {
1567
+ /**
1568
+ * 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.
1569
+ */
1570
+ experimental?: unknown;
1571
+ /**
1572
+ * 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.
1573
+ */
1574
+ deprecated?: boolean;
1575
+ /**
1576
+ * 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.
1577
+ */
1578
+ v1_translatable?: unknown;
1579
+ /**
1580
+ * 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.
1581
+ */
1582
+ since_version?: string;
1583
+ /**
1584
+ * 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').
1585
+ */
1586
+ migration_target_version?: string;
1587
+ /**
1588
+ * 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).
1589
+ */
1590
+ composition_model?: 'deterministic' | 'algorithmic';
1591
+ /**
1592
+ * 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.
1593
+ */
1594
+ provenance_required?: boolean;
1595
+ /**
1596
+ * 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.
1597
+ *
1598
+ * **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.
1599
+ */
1600
+ platform_extensions?: PlatformExtensionReference[];
1601
+ /**
1602
+ * 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.
1603
+ *
1604
+ * **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.
1605
+ */
1606
+ synthesis_nondeterministic?: boolean;
1607
+ slots?: unknown;
1608
+ /**
1609
+ * 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).
1610
+ */
1611
+ production_window_business_days?: number;
1612
+ /**
1613
+ * Catalog types this product accepts.
1614
+ */
1615
+ supported_catalog_types?: ('product' | 'store' | 'offering' | 'hotel' | 'flight' | 'vehicle' | 'real_estate' | 'education' | 'destination' | 'app' | 'job' | 'inventory')[];
1616
+ /**
1617
+ * Minimum catalog item count buyer must supply.
1618
+ * @minimum 1
1619
+ */
1620
+ min_items?: number;
1621
+ /**
1622
+ * Maximum items considered for placement.
1623
+ */
1624
+ max_items?: number;
1625
+ /**
1626
+ * 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.
1627
+ */
1628
+ fanout_mode?: 'per_item' | 'multi_item_in_creative' | 'single_item';
1629
+ /**
1630
+ * Catalog item fields the seller requires (e.g., ['title', 'image_url', 'price']).
1631
+ */
1632
+ required_catalog_fields?: string[];
1633
+ /**
1634
+ * Catalog identifier types the placement renders against.
1635
+ */
1636
+ 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')[];
1637
+ /**
1638
+ * Whether the buyer can supply a hero/banner asset alongside the catalog (Pinterest Collection pattern).
1639
+ */
1640
+ hero_asset_supported?: boolean;
1641
+ /**
1642
+ * 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.
1643
+ */
1644
+ item_production_model?: 'buyer_uploaded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1645
+ }
1646
+
1647
+ /**
1648
+ * 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).
1649
+ */
1650
+ export interface CanonicalFormatVASTVideo {
1651
+ /**
1652
+ * 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`).
1653
+ *
1654
+ * Three drivers of `experimental: true`:
1655
+ * 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).
1656
+ * 2. **Adopter runtime gap** — the seller has declared the canonical in their catalog but their runtime doesn't yet honor it cleanly.
1657
+ * 3. **Custom shapes** — `format_kind: "custom"` is inherently experimental until the working group promotes a `format_shape` to a first-class canonical.
1658
+ *
1659
+ * 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).
1660
+ */
1661
+ experimental?: boolean;
1662
+ /**
1663
+ * 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.
1664
+ */
1665
+ deprecated?: boolean;
1666
+ /**
1667
+ * 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.
1668
+ *
1669
+ * 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`.
1670
+ */
1671
+ v1_translatable?: boolean;
1672
+ /**
1673
+ * 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.
1674
+ */
1675
+ since_version?: string;
1676
+ /**
1677
+ * 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').
1678
+ */
1679
+ migration_target_version?: string;
1680
+ /**
1681
+ * 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).
1682
+ */
1683
+ composition_model?: 'deterministic' | 'algorithmic';
1684
+ /**
1685
+ * 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.
1686
+ */
1687
+ provenance_required?: boolean;
1688
+ /**
1689
+ * 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.
1690
+ *
1691
+ * **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.
1692
+ */
1693
+ platform_extensions?: PlatformExtensionReference[];
1694
+ /**
1695
+ * 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.
1696
+ *
1697
+ * **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.
1698
+ */
1699
+ synthesis_nondeterministic?: boolean;
1700
+ /**
1701
+ * 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.
1702
+ */
1703
+ slots?: unknown;
1704
+ /**
1705
+ * 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).
1706
+ */
1707
+ production_window_business_days?: number;
1708
+ orientation?: 'vertical' | 'horizontal' | 'square';
1709
+ /**
1710
+ * @pattern ^[0-9]+(\.[0-9]+)?:[0-9]+(\.[0-9]+)?$
1711
+ */
1712
+ aspect_ratio?: string;
1713
+ /**
1714
+ * Required VAST version.
1715
+ */
1716
+ vast_version?: '2.0' | '3.0' | '4.0' | '4.1' | '4.2';
1717
+ /**
1718
+ * Whether VPAID interactivity is supported. When true, the VAST tag may carry VPAID JS/Flash payloads.
1719
+ */
1720
+ vpaid_enabled?: boolean;
1721
+ vpaid_version?: '1.0' | '2.0';
1722
+ /**
1723
+ * Whether IAB SIMID interactive video extensions are supported.
1724
+ */
1725
+ simid_supported?: boolean;
1726
+ /**
1727
+ * [min, max] duration in milliseconds. **Precedence**: `duration_ms_exact` takes precedence when both ship. SDKs SHOULD lint a warning when both fields ship.
1728
+ */
1729
+ duration_ms_range?: number[];
1730
+ /**
1731
+ * When set, duration must equal exactly this value. Takes precedence over `duration_ms_range` when both ship.
1732
+ * @minimum 1
1733
+ */
1734
+ duration_ms_exact?: number;
1735
+ /**
1736
+ * @minimum 1
1737
+ */
1738
+ min_width?: number;
1739
+ /**
1740
+ * @minimum 1
1741
+ */
1742
+ max_width?: number;
1743
+ /**
1744
+ * @minimum 1
1745
+ */
1746
+ min_height?: number;
1747
+ /**
1748
+ * @minimum 1
1749
+ */
1750
+ max_height?: number;
1751
+ /**
1752
+ * Whether the VAST creative must be linear (non-skippable in-stream).
1753
+ */
1754
+ linear_required?: boolean;
1755
+ /**
1756
+ * When skippable, the buyer-side skip threshold in milliseconds (e.g., 5000 for 5-second skippable pre-roll).
1757
+ * @minimum 0
1758
+ */
1759
+ skippable_after_ms?: number;
1760
+ /**
1761
+ * Maximum VAST wrapper redirect depth permitted.
1762
+ * @minimum 0
1763
+ */
1764
+ max_wrapper_depth?: number;
1765
+ ssl_required?: boolean;
1766
+ }
1767
+
1768
+ /**
1769
+ * Optional v2 canonical-projection annotation. Always an object — bare-string shorthand (`canonical: "image"`) is not supported; the minimal form is `canonical: { "kind": "image" }`. Carries `kind` (which canonical the v1 format projects to) plus optional `asset_source` and `slots_override` for cases where the v1 format's shape doesn't follow the canonical's defaults (e.g., generative entries whose input is `generation_prompt: text` instead of `image_main: image`).
1770
+ *
1771
+ * When set, SDKs use this annotation as the authoritative v1 → v2 mapping for this format, bypassing the [v1 canonical mapping registry](/schemas/registries/v1-canonical-mapping.json) lookup. Combined with the slot-level `asset_group_id` declarations on each `assets[i]` entry, a v1 format declaration with `canonical` set is fully self-describing for v1↔v2 translation.
1772
+ *
1773
+ * Resolution order for SDK projection from v1 wire shape to v2 (per RFC #3305 amendment #3767):
1774
+ * 1. If this `canonical` field is set, use it (seller-declared, highest priority). Apply `asset_source` and `slots_override` from the projection ref when present; otherwise inherit the canonical's defaults.
1775
+ * 2. Else, look up `format_id` in the canonical mapping registry's `format_id_glob` entries.
1776
+ * 3. Else, attempt structural match against the registry's `structural` entries (asset types, slot shape, vast_versions, etc.).
1777
+ * 4. Else, fail closed: SDK MUST NOT emit `format_options` for products carrying this format. Surface `FORMAT_PROJECTION_FAILED` on the response `errors[]` suggesting the seller add an explicit `canonical` annotation or file a registry entry.
1778
+ *
1779
+ * When `canonical.kind` is `custom`, the seller MUST also declare `canonical_format_shape` and `canonical_format_schema` (parallel to ProductFormatDeclaration's `format_shape` and `format_schema`) so buyer SDKs can fetch the seller's custom format schema.
1780
+ *
1781
+ * See `canonical-projection-ref.json` for full projection semantics and examples (default-slot case, generative case, brief-driven case).
1782
+ */
1783
+ export interface CanonicalProjectionReference {
1784
+ kind: CanonicalFormatKind;
1785
+ /**
1786
+ * Where the rendered asset bytes come from on the projected v2 declaration. Default (when omitted) is `buyer_uploaded` — the canonical's default. Set explicitly when the v1 named format doesn't follow that default. Required for generative entries (`agent_synthesized` or `seller_pre_rendered_from_brief`) because their asset shape doesn't carry image/video/audio bytes — projection without this hint produces a lossy v2 declaration that claims buyer-uploaded bytes.
1787
+ */
1788
+ asset_source?: 'buyer_uploaded' | 'publisher_host_recorded' | 'seller_pre_rendered_from_brief' | 'seller_human_designed' | 'agent_synthesized';
1789
+ /**
1790
+ * When the v1 named format's slot shape differs from the canonical's default slots, this carries the override that the projected v2 declaration's `params.slots[]` should use. REPLACES (does not merge with) the canonical's default slots — projection-time semantics. The slot vocabulary follows `asset-group-vocabulary.json`. Asset IDs in the v1 format's `assets[*]` MUST resolve (directly or via the vocabulary's aliases) to the `asset_group_id` values declared here.
1791
+ */
1792
+ slots_override?: {
1793
+ /**
1794
+ * Asset group identifier from `asset-group-vocabulary.json` (e.g., `generation_prompt`, `creative_brief`, `image_main`, `video_main`).
1795
+ */
1796
+ asset_group_id: string;
1797
+ /**
1798
+ * Asset type — `image`, `video`, `audio`, `text`, `html`, `javascript`, `url`, `zip`, `brief`.
1799
+ */
1800
+ asset_type: string;
1801
+ /**
1802
+ * Whether the slot is required in the projected declaration.
1803
+ */
1804
+ required?: boolean;
1805
+ /**
1806
+ * Max character count for text slots.
1807
+ * @minimum 1
1808
+ */
1809
+ max_chars?: number;
1810
+ /**
1811
+ * When false, slot is for moderation/review only and is NOT consumed by the seller's renderer (e.g., a brand-safety brief that informs review but doesn't appear in the rendered ad).
1812
+ */
1813
+ consumed_for_production?: boolean;
1814
+ }[];
1815
+ }
1816
+
1817
+ /**
1818
+ * 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.
1819
+ */
1820
+ export interface ContextObject {
1821
+ }
1822
+
1823
+ /**
1824
+ * Fixed cost per thousand impressions
1825
+ */
1826
+ export interface CpmPricing {
1827
+ model: 'cpm';
1828
+ /**
1829
+ * Cost per thousand impressions
1830
+ * @minimum 0
1831
+ */
1832
+ cpm: number;
1833
+ /**
1834
+ * ISO 4217 currency code
1835
+ * @pattern ^[A-Z]{3}$
1836
+ */
1837
+ currency: string;
1838
+ ext?: ExtensionObject;
1839
+ }
1840
+
1841
+ /**
1842
+ * Capabilities supported by creative agents for format handling
1843
+ */
1844
+ export type CreativeAgentCapability = 'validation' | 'assembly' | 'generation' | 'preview' | 'delivery';
1845
+
1846
+ /**
1847
+ * 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.
1848
+ */
1849
+ export interface CustomFormatDeclaration {
1850
+ format_kind: 'custom';
1851
+ /**
1852
+ * Custom shape's params. Validated against the schema fetched from `format_schema.uri` at the cached `format_schema.digest`.
1853
+ */
1854
+ params: {};
1855
+ }
1856
+
1857
+ /**
1858
+ * Escape hatch for pricing constructs that do not fit cpm, percent_of_media, flat_fee, or per_unit. Use when a vendor prices via performance kickers, tiered volume, hybrid formulas, outcome-sharing, or any other model the standard forms cannot express. Requires a human-readable description and a structured metadata object that captures the parameters a buyer needs to reason about the charge. Buyers SHOULD route custom pricing through operator review before commitment — automatic selection is not recommended.
1859
+ */
1860
+ export interface CustomPricing {
1861
+ model: 'custom';
1862
+ /**
1863
+ * Human-readable description of the custom pricing model. Buyers display this to the operator when requesting approval.
1864
+ * @minLength 1
1865
+ */
1866
+ description: string;
1867
+ /**
1868
+ * Structured parameters for the custom model. Keys follow lowercase_snake_case. Values may be primitives, arrays, or nested objects. Must be sufficient for a human to understand the pricing basis and for a downstream system to reconstruct the charge. Vendors SHOULD include a `summary_for_operator` string (one or two sentences, suitable for display in a buyer's operator-review UI) so reviewers across vendors see a consistent prompt. Required operator-review fields (approver role, dollar threshold for automatic approval, escalation contact) MAY be surfaced via additional keys the buyer's review surface recognizes.
1869
+ */
1870
+ metadata: {
1871
+ /**
1872
+ * One or two sentences describing the pricing construct in plain language, displayed to the buyer's operator when requesting approval. Should not repeat the top-level `description` verbatim — summarize the charge mechanic instead (e.g., 'Base $12 CPM plus $0.50 per qualifying post-view conversion, capped at $45 CPM').
1873
+ * @minLength 1
1874
+ */
1875
+ summary_for_operator?: string;
1876
+ };
1877
+ /**
1878
+ * ISO 4217 currency code. Present when the pricing resolves to a monetary charge in a specific currency.
1879
+ * @pattern ^[A-Z]{3}$
1880
+ */
1881
+ currency?: string;
1882
+ ext?: ExtensionObject;
1883
+ }
1884
+
1885
+ /**
1886
+ * Requirements for DAAST (Digital Audio Ad Serving Template) creative assets.
1887
+ */
1888
+ export interface DAASTAssetRequirements {
1889
+ /**
1890
+ * Required DAAST version. DAAST 1.0 is the current IAB standard.
1891
+ */
1892
+ daast_version?: '1.0';
1893
+ }
1894
+
1895
+ export interface DAASTAudioFormatDeclaration {
1896
+ format_kind: 'audio_daast';
1897
+ params: CanonicalFormatDAASTAudio;
1898
+ }
1899
+
1900
+ /**
1901
+ * Unit of measurement for width/height values. Defaults to 'px' when absent. Print formats use 'inches' or 'cm'.
1902
+ */
1903
+ export type DimensionUnit = 'px' | 'dp' | 'inches' | 'cm' | 'mm' | 'pt';
1904
+
1905
+ /**
1906
+ * How long the disclosure must persist during content playback or display
1907
+ */
1908
+ export type DisclosurePersistence = 'continuous' | 'initial' | 'flexible';
1909
+
1910
+ /**
1911
+ * Where a required disclosure should appear within a creative. Used by creative briefs to specify disclosure placement and by formats to declare which positions they can render.
1912
+ */
1913
+ export type DisclosurePosition = 'prominent' | 'footer' | 'audio' | 'subtitle' | 'overlay' | 'end_card' | 'pre_roll' | 'companion';
1914
+
1915
+ export interface DisplayTagFormatDeclaration {
1916
+ format_kind: 'display_tag';
1917
+ params: CanonicalFormatDisplayTag;
1918
+ }
1919
+
1920
+ /**
1921
+ * 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.
1922
+ */
1923
+ export interface ExtensionObject {
1924
+ }
1925
+
1926
+ export interface Fixed {
1927
+ [k: string]: unknown | undefined;
1928
+ }
1929
+
1930
+ /**
1931
+ * Fixed charge per billing period, regardless of impressions or spend. Used for licensed data bundles and audience subscriptions.
1932
+ */
1933
+ export interface FlatFeePricing {
1934
+ model: 'flat_fee';
1935
+ /**
1936
+ * Fixed charge for the billing period
1937
+ * @minimum 0
1938
+ */
1939
+ amount: number;
1940
+ /**
1941
+ * Billing period for the flat fee.
1942
+ */
1943
+ period: 'monthly' | 'quarterly' | 'annual' | 'campaign';
1944
+ /**
1945
+ * ISO 4217 currency code
1946
+ * @pattern ^[A-Z]{3}$
1947
+ */
1948
+ currency: string;
1949
+ ext?: ExtensionObject;
1950
+ }
1951
+
1952
+ /**
1953
+ * Represents a creative format with its requirements
1954
+ */
1955
+ export interface Format {
1956
+ format_id: FormatReferenceStructuredObject;
1957
+ /**
1958
+ * Human-readable format name
1959
+ */
1960
+ name: string;
1961
+ /**
1962
+ * Plain text explanation of what this format does and what assets it requires
1963
+ */
1964
+ description?: string;
1965
+ /**
1966
+ * Optional URL to showcase page with examples and interactive demos of this format
1967
+ */
1968
+ example_url?: string;
1969
+ /**
1970
+ * List of parameters this format accepts in format_id. Template formats define which parameters (dimensions, duration, etc.) can be specified when instantiating the format. Empty or omitted means this is a concrete format with fixed parameters.
1971
+ */
1972
+ accepts_parameters?: FormatIDParameter[];
1973
+ /**
1974
+ * Specification of rendered pieces for this format. Most formats produce a single render. Companion ad formats (video + banner), adaptive formats, and multi-placement formats produce multiple renders. Each render specifies its role and dimensions.
1975
+ */
1976
+ renders?: ({
1977
+ /**
1978
+ * Semantic role of this rendered piece (e.g., 'primary', 'companion', 'mobile_variant')
1979
+ */
1980
+ role: string;
1981
+ /**
1982
+ * Dimensions for this rendered piece. Defaults to pixels when unit is absent.
1983
+ */
1984
+ dimensions: {
1985
+ /**
1986
+ * Fixed width. Interpretation depends on unit (default: pixels).
1987
+ */
1988
+ width?: number;
1989
+ /**
1990
+ * Fixed height. Interpretation depends on unit (default: pixels).
1991
+ */
1992
+ height?: number;
1993
+ /**
1994
+ * Minimum width for responsive renders
1995
+ */
1996
+ min_width?: number;
1997
+ /**
1998
+ * Minimum height for responsive renders
1999
+ */
2000
+ min_height?: number;
2001
+ /**
2002
+ * Maximum width for responsive renders
2003
+ */
2004
+ max_width?: number;
2005
+ /**
2006
+ * Maximum height for responsive renders
2007
+ */
2008
+ max_height?: number;
2009
+ unit?: DimensionUnit;
2010
+ /**
2011
+ * Indicates which dimensions are responsive/fluid
2012
+ */
2013
+ responsive?: {
2014
+ width: boolean;
2015
+ height: boolean;
2016
+ };
2017
+ /**
2018
+ * Fixed aspect ratio constraint (e.g., '16:9', '4:3', '1:1', '1.91:1')
2019
+ * @pattern ^\d+(\.\d+)?:\d+(\.\d+)?$
2020
+ */
2021
+ aspect_ratio?: string;
2022
+ };
2023
+ } | {
2024
+ /**
2025
+ * Semantic role of this rendered piece (e.g., 'primary', 'companion', 'mobile_variant')
2026
+ */
2027
+ role: string;
2028
+ parameters_from_format_id: true;
2029
+ })[];
2030
+ /**
2031
+ * Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory.
2032
+ */
2033
+ assets?: FormatAssetSlot[];
2034
+ /**
2035
+ * Delivery method specifications (e.g., hosted, VAST, third-party tags)
2036
+ */
2037
+ delivery?: {};
2038
+ /**
2039
+ * List of universal macros supported by this format (e.g., MEDIA_BUY_ID, CACHEBUSTER, DEVICE_ID). Used for validation and developer tooling. See docs/creative/universal-macros.mdx for full documentation.
2040
+ */
2041
+ supported_macros?: (UniversalMacro | string)[];
2042
+ /**
2043
+ * Array of format IDs this format accepts as input creative manifests. When present, indicates this format can take existing creatives in these formats as input. Omit for formats that work from raw assets (images, text, etc.) rather than existing creatives.
2044
+ */
2045
+ input_format_ids?: FormatReferenceStructuredObject[];
2046
+ /**
2047
+ * Array of format IDs that this format can produce as output. When present, indicates this format can build creatives in these output formats (e.g., a multi-publisher template format might produce standard display formats across many publishers). Omit for formats that produce a single fixed output (the format itself).
2048
+ */
2049
+ output_format_ids?: FormatReferenceStructuredObject[];
2050
+ /**
2051
+ * Optional standard visual card (300x400px) for displaying this format in user interfaces. Can be rendered via preview_creative or pre-generated.
2052
+ */
2053
+ format_card?: {
2054
+ format_id: FormatReferenceStructuredObject;
2055
+ /**
2056
+ * Asset manifest for rendering the card, structure defined by the format
2057
+ */
2058
+ manifest: {};
2059
+ };
2060
+ /**
2061
+ * Accessibility posture of this format. Declares the WCAG conformance level that creatives produced by this format will meet.
2062
+ */
2063
+ accessibility?: {
2064
+ wcag_level: WCAGLevel;
2065
+ /**
2066
+ * When true, all assets with x-accessibility fields must include those fields. For inspectable assets (image, video, audio), this means providing accessibility metadata like alt_text or captions. For opaque assets (HTML, JavaScript), this means providing self-declared accessibility properties.
2067
+ */
2068
+ requires_accessible_assets?: boolean;
2069
+ };
2070
+ /**
2071
+ * Disclosure positions this format can render. Buyers use this to determine whether a format can satisfy their compliance requirements before submitting a creative. When omitted, the format makes no disclosure rendering guarantees — creative agents SHOULD treat this as incompatible with briefs that require specific disclosure positions. Values correspond to positions on creative-brief.json required_disclosures.
2072
+ */
2073
+ supported_disclosure_positions?: DisclosurePosition[];
2074
+ /**
2075
+ * Structured disclosure capabilities per position with persistence modes. Declares which persistence behaviors each disclosure position supports, enabling persistence-aware matching against provenance render guidance and brief requirements. When present, supersedes supported_disclosure_positions for persistence-aware queries. The flat supported_disclosure_positions field is retained for backward compatibility. Each position MUST appear at most once; validators and agents SHOULD reject duplicates.
2076
+ */
2077
+ disclosure_capabilities?: {
2078
+ position: DisclosurePosition;
2079
+ /**
2080
+ * Persistence modes this position supports
2081
+ */
2082
+ persistence: DisclosurePersistence[];
2083
+ }[];
2084
+ /**
2085
+ * Optional detailed card with carousel and full specifications. Provides rich format documentation similar to ad spec pages.
2086
+ */
2087
+ format_card_detailed?: {
2088
+ format_id: FormatReferenceStructuredObject;
2089
+ /**
2090
+ * Asset manifest for rendering the detailed card, structure defined by the format
2091
+ */
2092
+ manifest: {};
2093
+ };
2094
+ /**
2095
+ * Metrics this format can produce in delivery reporting. Buyers receive the intersection of format reported_metrics and product available_metrics. If omitted, the format defers entirely to product-level metric declarations.
2096
+ */
2097
+ reported_metrics?: AvailableMetric[];
2098
+ /**
2099
+ * Pricing options for this format. Used by transformation and generation agents that charge per format adapted, per image generated, or per unit of work. Present when the request included include_pricing=true and account. Ad servers and library-based agents expose pricing on list_creatives instead.
2100
+ */
2101
+ pricing_options?: VendorPricingOption[];
2102
+ canonical?: CanonicalProjectionReference;
2103
+ canonical_parameters?: ProductFormatDeclaration;
2104
+ }
2105
+
2106
+ export type FormatAssetSlot = IndividualAssetSlot | RepeatableGroupAsset;
2107
+
2108
+ /**
2109
+ * Types of parameters that template formats accept in format_id objects to create parameterized format identifiers
2110
+ */
2111
+ export type FormatIDParameter = 'dimensions' | 'duration';
2112
+
2113
+ /**
2114
+ * 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.
2115
+ */
2116
+ export interface FormatReferenceStructuredObject {
2117
+ /**
2118
+ * 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.
2119
+ */
2120
+ agent_url: string;
2121
+ /**
2122
+ * 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.
2123
+ * @pattern ^[a-zA-Z0-9_-]+$
2124
+ */
2125
+ id: string;
2126
+ /**
2127
+ * 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.
2128
+ * @minimum 1
2129
+ */
2130
+ width?: number;
2131
+ /**
2132
+ * 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.
2133
+ * @minimum 1
2134
+ */
2135
+ height?: number;
2136
+ /**
2137
+ * Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.
2138
+ * @minimum 1
2139
+ */
2140
+ duration_ms?: number;
2141
+ }
2142
+
2143
+ /**
2144
+ * Whether the video uses a constant or variable frame rate. Broadcast and SSAI contexts require constant frame rate for seamless splicing.
2145
+ */
2146
+ export type FrameRateType = 'constant' | 'variable';
2147
+
2148
+ /**
2149
+ * Group of Pictures structure. SSAI and broadcast require closed GOPs for clean splice points; open GOPs may produce artifacts at ad boundaries.
2150
+ */
2151
+ export type GOPType = 'closed' | 'open';
2152
+
2153
+ export type GroupAssetSlot = GroupImageAsset | GroupVideoAsset | GroupAudioAsset | GroupTextAsset | GroupMarkdownAsset | GroupHtmlAsset | GroupCssAsset | GroupJavaScriptAsset | GroupVastAsset | GroupDaastAsset | GroupUrlAsset | GroupWebhookAsset;
2154
+
2155
+ /**
2156
+ * Audio asset in group
2157
+ */
2158
+ export type GroupAudioAsset = BaseGroupAsset & {
2159
+ asset_type: 'audio';
2160
+ requirements?: AudioAssetRequirements;
2161
+ };
2162
+
2163
+ /**
2164
+ * CSS asset in group
2165
+ */
2166
+ export type GroupCssAsset = BaseGroupAsset & {
2167
+ asset_type: 'css';
2168
+ requirements?: CSSAssetRequirements;
2169
+ };
2170
+
2171
+ /**
2172
+ * DAAST asset in group
2173
+ */
2174
+ export type GroupDaastAsset = BaseGroupAsset & {
2175
+ asset_type: 'daast';
2176
+ requirements?: DAASTAssetRequirements;
2177
+ };
2178
+
2179
+ /**
2180
+ * HTML asset in group
2181
+ */
2182
+ export type GroupHtmlAsset = BaseGroupAsset & {
2183
+ asset_type: 'html';
2184
+ requirements?: HTMLAssetRequirements;
2185
+ };
2186
+
2187
+ /**
2188
+ * Image asset in group
2189
+ */
2190
+ export type GroupImageAsset = BaseGroupAsset & {
2191
+ asset_type: 'image';
2192
+ requirements?: ImageAssetRequirements;
2193
+ };
2194
+
2195
+ /**
2196
+ * JavaScript asset in group
2197
+ */
2198
+ export type GroupJavaScriptAsset = BaseGroupAsset & {
2199
+ asset_type: 'javascript';
2200
+ requirements?: JavaScriptAssetRequirements;
2201
+ };
2202
+
2203
+ /**
2204
+ * Markdown asset in group
2205
+ */
2206
+ export type GroupMarkdownAsset = BaseGroupAsset & {
2207
+ asset_type: 'markdown';
2208
+ requirements?: MarkdownAssetRequirements;
2209
+ };
2210
+
2211
+ /**
2212
+ * Text asset in group
2213
+ */
2214
+ export type GroupTextAsset = BaseGroupAsset & {
2215
+ asset_type: 'text';
2216
+ requirements?: TextAssetRequirements;
2217
+ };
2218
+
2219
+ /**
2220
+ * URL asset in group
2221
+ */
2222
+ export type GroupUrlAsset = BaseGroupAsset & {
2223
+ asset_type: 'url';
2224
+ requirements?: URLAssetRequirements;
2225
+ };
2226
+
2227
+ /**
2228
+ * VAST asset in group
2229
+ */
2230
+ export type GroupVastAsset = BaseGroupAsset & {
2231
+ asset_type: 'vast';
2232
+ requirements?: VASTAssetRequirements;
2233
+ };
2234
+
2235
+ /**
2236
+ * Video asset in group
2237
+ */
2238
+ export type GroupVideoAsset = BaseGroupAsset & {
2239
+ asset_type: 'video';
2240
+ requirements?: VideoAssetRequirements;
2241
+ };
2242
+
2243
+ /**
2244
+ * Webhook asset in group
2245
+ */
2246
+ export type GroupWebhookAsset = BaseGroupAsset & {
2247
+ asset_type: 'webhook';
2248
+ requirements?: WebhookAssetRequirements;
2249
+ };
2250
+
2251
+ export interface HTML5FormatDeclaration {
2252
+ format_kind: 'html5';
2253
+ params: CanonicalFormatHTML5Banner;
2254
+ }
2255
+
2256
+ /**
2257
+ * Requirements for HTML creative assets. These define the execution environment constraints that the HTML must be compatible with.
2258
+ */
2259
+ export interface HTMLAssetRequirements {
2260
+ /**
2261
+ * Maximum file size in kilobytes for the HTML asset
2262
+ * @minimum 1
2263
+ */
2264
+ max_file_size_kb?: number;
2265
+ /**
2266
+ * Sandbox environment the HTML must be compatible with. 'none' = direct DOM access, 'iframe' = standard iframe isolation, 'safeframe' = IAB SafeFrame container, 'fencedframe' = Privacy Sandbox fenced frame
2267
+ */
2268
+ sandbox?: 'none' | 'iframe' | 'safeframe' | 'fencedframe';
2269
+ /**
2270
+ * Whether the HTML creative can load external resources (scripts, images, fonts, etc.). When false, all resources must be inlined or bundled.
2271
+ */
2272
+ external_resources_allowed?: boolean;
2273
+ /**
2274
+ * List of domains the HTML creative may reference for external resources. Only applicable when external_resources_allowed is true.
2275
+ */
2276
+ allowed_external_domains?: string[];
2277
+ }
2278
+
2279
+ export interface HostedAudioFormatDeclaration {
2280
+ format_kind: 'audio_hosted';
2281
+ params: CanonicalFormatHostedAudio;
2282
+ }
2283
+
2284
+ export interface HostedVideoFormatDeclaration {
2285
+ format_kind: 'video_hosted';
2286
+ params: CanonicalFormatHostedVideo;
2287
+ }
2288
+
2289
+ /**
2290
+ * Requirements for image creative assets. These define the technical constraints for image files.
2291
+ */
2292
+ export interface ImageAssetRequirements {
2293
+ /**
2294
+ * Minimum width. Interpretation depends on unit (default: pixels). For exact dimensions, set min_width = max_width.
2295
+ */
2296
+ min_width?: number;
2297
+ /**
2298
+ * Maximum width. Interpretation depends on unit (default: pixels). For exact dimensions, set min_width = max_width.
2299
+ */
2300
+ max_width?: number;
2301
+ /**
2302
+ * Minimum height. Interpretation depends on unit (default: pixels). For exact dimensions, set min_height = max_height.
2303
+ */
2304
+ min_height?: number;
2305
+ /**
2306
+ * Maximum height. Interpretation depends on unit (default: pixels). For exact dimensions, set min_height = max_height.
2307
+ */
2308
+ max_height?: number;
2309
+ unit?: DimensionUnit;
2310
+ /**
2311
+ * Required aspect ratio (e.g., '16:9', '1:1', '1.91:1')
2312
+ * @pattern ^\d+(\.\d+)?:\d+(\.\d+)?$
2313
+ */
2314
+ aspect_ratio?: string;
2315
+ /**
2316
+ * Accepted image file formats
2317
+ */
2318
+ formats?: ('jpg' | 'jpeg' | 'png' | 'gif' | 'webp' | 'svg' | 'avif' | 'tiff' | 'pdf' | 'eps')[];
2319
+ /**
2320
+ * Minimum resolution in dots per inch. Always in DPI regardless of the dimension unit. Standard print requires 300 DPI, newspaper 150 DPI.
2321
+ * @minimum 1
2322
+ */
2323
+ min_dpi?: number;
2324
+ /**
2325
+ * Required bleed area beyond the trim size. The submitted image must be larger than the declared dimensions: total width = trim width + left bleed + right bleed, total height = trim height + top bleed + bottom bleed. For uniform bleed: total = trim + (2 * uniform). Uses the same unit as the parent dimensions.
2326
+ */
2327
+ bleed?: {
2328
+ /**
2329
+ * Same bleed on all four sides
2330
+ * @minimum 0
2331
+ */
2332
+ uniform: number;
2333
+ } | {
2334
+ /**
2335
+ * @minimum 0
2336
+ */
2337
+ top: number;
2338
+ /**
2339
+ * @minimum 0
2340
+ */
2341
+ right: number;
2342
+ /**
2343
+ * @minimum 0
2344
+ */
2345
+ bottom: number;
2346
+ /**
2347
+ * @minimum 0
2348
+ */
2349
+ left: number;
2350
+ };
2351
+ /**
2352
+ * Required color space. Print typically requires CMYK.
2353
+ */
2354
+ color_space?: 'rgb' | 'cmyk' | 'grayscale';
2355
+ /**
2356
+ * Maximum file size in kilobytes
2357
+ * @minimum 1
2358
+ */
2359
+ max_file_size_kb?: number;
2360
+ /**
2361
+ * Whether the image must support transparency (requires PNG, WebP, or GIF)
2362
+ */
2363
+ transparency_required?: boolean;
2364
+ /**
2365
+ * Whether animated images (GIF, animated WebP) are accepted
2366
+ */
2367
+ animation_allowed?: boolean;
2368
+ /**
2369
+ * Maximum animation duration in milliseconds (if animation_allowed is true)
2370
+ * @minimum 0
2371
+ */
2372
+ max_animation_duration_ms?: number;
2373
+ /**
2374
+ * Maximum weight in grams for the finished physical piece (print inserts, flyers). Affects postage calculations and production constraints. Only applicable to print channels.
2375
+ */
2376
+ max_weight_grams?: number;
2377
+ }
2378
+
2379
+ export interface ImageCarouselFormatDeclaration {
2380
+ format_kind: 'image_carousel';
2381
+ params: CanonicalFormatImageCarousel;
2382
+ }
2383
+
2384
+ export interface ImageFormatDeclaration {
2385
+ format_kind: 'image';
2386
+ params: CanonicalFormatImage;
2387
+ }
2388
+
2389
+ export type IndividualAssetSlot = IndividualImageAsset | IndividualVideoAsset | IndividualAudioAsset | IndividualTextAsset | IndividualMarkdownAsset | IndividualHtmlAsset | IndividualCssAsset | IndividualJavaScriptAsset | IndividualVastAsset | IndividualDaastAsset | IndividualUrlAsset | IndividualWebhookAsset | IndividualBriefAsset | IndividualCatalogAsset;
2390
+
2391
+ /**
2392
+ * Audio asset
2393
+ */
2394
+ export type IndividualAudioAsset = BaseIndividualAsset & {
2395
+ asset_type: 'audio';
2396
+ requirements?: AudioAssetRequirements;
2397
+ };
2398
+
2399
+ /**
2400
+ * Brief asset
2401
+ */
2402
+ export type IndividualBriefAsset = BaseIndividualAsset & {
2403
+ asset_type: 'brief';
2404
+ };
2405
+
2406
+ /**
2407
+ * Catalog asset
2408
+ */
2409
+ export type IndividualCatalogAsset = BaseIndividualAsset & {
2410
+ asset_type: 'catalog';
2411
+ };
2412
+
2413
+ /**
2414
+ * CSS asset
2415
+ */
2416
+ export type IndividualCssAsset = BaseIndividualAsset & {
2417
+ asset_type: 'css';
2418
+ requirements?: CSSAssetRequirements;
2419
+ };
2420
+
2421
+ /**
2422
+ * DAAST asset
2423
+ */
2424
+ export type IndividualDaastAsset = BaseIndividualAsset & {
2425
+ asset_type: 'daast';
2426
+ requirements?: DAASTAssetRequirements;
2427
+ };
2428
+
2429
+ /**
2430
+ * HTML asset
2431
+ */
2432
+ export type IndividualHtmlAsset = BaseIndividualAsset & {
2433
+ asset_type: 'html';
2434
+ requirements?: HTMLAssetRequirements;
2435
+ };
2436
+
2437
+ /**
2438
+ * Image asset
2439
+ */
2440
+ export type IndividualImageAsset = BaseIndividualAsset & {
2441
+ asset_type: 'image';
2442
+ requirements?: ImageAssetRequirements;
2443
+ };
2444
+
2445
+ /**
2446
+ * JavaScript asset
2447
+ */
2448
+ export type IndividualJavaScriptAsset = BaseIndividualAsset & {
2449
+ asset_type: 'javascript';
2450
+ requirements?: JavaScriptAssetRequirements;
2451
+ };
2452
+
2453
+ /**
2454
+ * Markdown asset
2455
+ */
2456
+ export type IndividualMarkdownAsset = BaseIndividualAsset & {
2457
+ asset_type: 'markdown';
2458
+ requirements?: MarkdownAssetRequirements;
2459
+ };
2460
+
2461
+ /**
2462
+ * Text asset
2463
+ */
2464
+ export type IndividualTextAsset = BaseIndividualAsset & {
2465
+ asset_type: 'text';
2466
+ requirements?: TextAssetRequirements;
2467
+ };
2468
+
2469
+ /**
2470
+ * URL asset
2471
+ */
2472
+ export type IndividualUrlAsset = BaseIndividualAsset & {
2473
+ asset_type: 'url';
2474
+ requirements?: URLAssetRequirements;
2475
+ };
2476
+
2477
+ /**
2478
+ * VAST asset
2479
+ */
2480
+ export type IndividualVastAsset = BaseIndividualAsset & {
2481
+ asset_type: 'vast';
2482
+ requirements?: VASTAssetRequirements;
2483
+ };
2484
+
2485
+ /**
2486
+ * Video asset
2487
+ */
2488
+ export type IndividualVideoAsset = BaseIndividualAsset & {
2489
+ asset_type: 'video';
2490
+ requirements?: VideoAssetRequirements;
2491
+ };
2492
+
2493
+ /**
2494
+ * Webhook asset
2495
+ */
2496
+ export type IndividualWebhookAsset = BaseIndividualAsset & {
2497
+ asset_type: 'webhook';
2498
+ requirements?: WebhookAssetRequirements;
2499
+ };
2500
+
2501
+ /**
2502
+ * Requirements for JavaScript creative assets. These define the execution environment constraints that the JavaScript must be compatible with.
2503
+ */
2504
+ export interface JavaScriptAssetRequirements {
2505
+ /**
2506
+ * Maximum file size in kilobytes for the JavaScript asset
2507
+ * @minimum 1
2508
+ */
2509
+ max_file_size_kb?: number;
2510
+ /**
2511
+ * Required JavaScript module format. 'script' = classic script, 'module' = ES modules, 'iife' = immediately invoked function expression
2512
+ */
2513
+ module_type?: 'script' | 'module' | 'iife';
2514
+ /**
2515
+ * Whether the JavaScript must use strict mode
2516
+ */
2517
+ strict_mode_required?: boolean;
2518
+ /**
2519
+ * Whether the JavaScript can load external resources dynamically
2520
+ */
2521
+ external_resources_allowed?: boolean;
2522
+ /**
2523
+ * List of domains the JavaScript may reference for external resources. Only applicable when external_resources_allowed is true.
2524
+ */
2525
+ allowed_external_domains?: string[];
2526
+ }
2527
+
2528
+ /**
2529
+ * Requirements for markdown creative assets.
2530
+ */
2531
+ export interface MarkdownAssetRequirements {
2532
+ /**
2533
+ * Maximum character length
2534
+ * @minimum 1
2535
+ */
2536
+ max_length?: number;
2537
+ }
2538
+
2539
+ /**
2540
+ * 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.
2541
+ */
2542
+ 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';
2543
+
2544
+ /**
2545
+ * Position of the moov atom in an MP4 container. 'start' enables progressive download without buffering the entire file; required for streaming ad delivery.
2546
+ */
2547
+ export type MoovAtomPosition = 'start' | 'end';
2548
+
2549
+ export interface MultiSize {
2550
+ [k: string]: unknown | undefined;
2551
+ }
2552
+
2553
+ export interface NativeInFeedFormatDeclaration {
2554
+ format_kind: 'native_in_feed';
2555
+ params: CanonicalFormatNativeInFeed;
2556
+ }
2557
+
2558
+ export interface None {
2559
+ [k: string]: unknown | undefined;
2560
+ }
2561
+
2562
+ /**
2563
+ * A publisher-controlled element that renders on top of buyer creative content within the ad placement. Creative agents should avoid placing critical content (CTAs, logos, key copy) within overlay bounds.
2564
+ */
2565
+ export interface Overlay {
2566
+ /**
2567
+ * Identifier for this overlay (e.g., 'play_pause', 'volume', 'publisher_logo', 'carousel_prev', 'carousel_next')
2568
+ */
2569
+ id: string;
2570
+ /**
2571
+ * Human-readable explanation of what this overlay is and how buyers should account for it
2572
+ */
2573
+ description?: string;
2574
+ /**
2575
+ * Optional visual reference for this overlay element. Useful for creative agents compositing previews and for buyers understanding what will appear over their content. Must include at least one of: url, light, or dark.
2576
+ */
2577
+ visual?: {
2578
+ /**
2579
+ * URL to a theme-neutral overlay graphic (SVG or PNG). Use when a single file works for all backgrounds, e.g. an SVG using CSS custom properties or currentColor.
2580
+ */
2581
+ url?: string;
2582
+ /**
2583
+ * URL to the overlay graphic for use on light/bright backgrounds (SVG or PNG)
2584
+ */
2585
+ light?: string;
2586
+ /**
2587
+ * URL to the overlay graphic for use on dark backgrounds (SVG or PNG)
2588
+ */
2589
+ dark?: string;
2590
+ };
2591
+ /**
2592
+ * Position and size of the overlay relative to the asset's own top-left corner. See 'unit' for coordinate interpretation.
2593
+ */
2594
+ bounds: {
2595
+ /**
2596
+ * Horizontal offset from the asset's left edge
2597
+ */
2598
+ x: number;
2599
+ /**
2600
+ * Vertical offset from the asset's top edge
2601
+ */
2602
+ y: number;
2603
+ /**
2604
+ * Width of the overlay
2605
+ * @minimum 0
2606
+ */
2607
+ width: number;
2608
+ /**
2609
+ * Height of the overlay
2610
+ * @minimum 0
2611
+ */
2612
+ height: number;
2613
+ /**
2614
+ * 'px' = absolute pixels from asset top-left. 'fraction' = proportional to asset dimensions (0.0 = edge, 1.0 = opposite edge). 'inches', 'cm', 'mm', 'pt' (1/72 inch) = physical units for print overlays, measured from asset top-left.
2615
+ */
2616
+ unit: 'px' | 'fraction' | 'inches' | 'cm' | 'mm' | 'pt';
2617
+ };
2618
+ }
2619
+
2620
+ /**
2621
+ * Standard cursor-based pagination parameters for list operations
2622
+ */
2623
+ export interface PaginationRequest {
2624
+ /**
2625
+ * Maximum number of items to return per page
2626
+ * @minimum 1
2627
+ * @maximum 100
2628
+ */
2629
+ max_results?: number;
2630
+ /**
2631
+ * Opaque cursor from a previous response to fetch the next page
2632
+ */
2633
+ cursor?: string;
2634
+ }
2635
+
2636
+ /**
2637
+ * Standard cursor-based pagination metadata for list responses
2638
+ */
2639
+ export interface PaginationResponse {
2640
+ /**
2641
+ * Whether more results are available beyond this page
2642
+ */
2643
+ has_more: boolean;
2644
+ /**
2645
+ * Opaque cursor to pass in the next request to fetch the next page. Only present when has_more is true.
2646
+ */
2647
+ cursor?: string;
2648
+ /**
2649
+ * Total number of items matching the query across all pages. Optional because not all backends can efficiently compute this.
2650
+ * @minimum 0
2651
+ */
2652
+ total_count?: number;
2653
+ }
2654
+
2655
+ /**
2656
+ * Fixed price per unit of work. Used for creative transformation (per format), AI generation (per image, per token), and rendering (per variant). The unit field describes what is counted; unit_price is the cost per one unit.
2657
+ */
2658
+ export interface PerUnitPricing {
2659
+ model: 'per_unit';
2660
+ /**
2661
+ * What is counted — e.g. 'format', 'image', 'token', 'variant', 'render', 'evaluation'.
2662
+ */
2663
+ unit: string;
2664
+ /**
2665
+ * Cost per one unit
2666
+ * @minimum 0
2667
+ */
2668
+ unit_price: number;
2669
+ /**
2670
+ * ISO 4217 currency code
2671
+ * @pattern ^[A-Z]{3}$
2672
+ */
2673
+ currency: string;
2674
+ ext?: ExtensionObject;
2675
+ }
2676
+
2677
+ /**
2678
+ * Percentage of media spend charged for this signal. When max_cpm is set, the effective rate is capped at that CPM — useful for platforms like The Trade Desk that use percent-of-media pricing with a CPM ceiling.
2679
+ */
2680
+ export interface PercentOfMediaPricing {
2681
+ model: 'percent_of_media';
2682
+ /**
2683
+ * Percentage of media spend, e.g. 15 = 15%
2684
+ * @minimum 0
2685
+ * @maximum 100
2686
+ */
2687
+ percent: number;
2688
+ /**
2689
+ * Optional CPM cap. When set, the effective charge is min(percent × media_spend_per_mille, max_cpm).
2690
+ * @minimum 0
2691
+ */
2692
+ max_cpm?: number;
2693
+ /**
2694
+ * ISO 4217 currency code for the resulting charge
2695
+ * @pattern ^[A-Z]{3}$
2696
+ */
2697
+ currency: string;
2698
+ ext?: ExtensionObject;
2699
+ }
2700
+
2701
+ /**
2702
+ * 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.
2703
+ *
2704
+ * **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.
2705
+ *
2706
+ * - **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`).
2707
+ * - **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.
2708
+ * - **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.
2709
+ * - **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.
2710
+ * - **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).
2711
+ * - **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).
2712
+ * - **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.
2713
+ * - **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.
2714
+ * - **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.
2715
+ * - **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.
2716
+ * - **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.
2717
+ */
2718
+ export interface PlatformExtensionReference {
2719
+ /**
2720
+ * 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.
2721
+ * @pattern ^https:\/\/
2722
+ */
2723
+ uri: string;
2724
+ /**
2725
+ * 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.
2726
+ * @pattern ^sha256:[a-f0-9]{64}$
2727
+ */
2728
+ digest: string;
2729
+ }
2730
+
2731
+ /**
2732
+ * 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.
2733
+ *
2734
+ * **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.
2735
+ *
2736
+ * **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.
2737
+ */
2738
+ export type ProductFormatDeclaration = {
2739
+ [k: string]: unknown | undefined;
2740
+ } & {
2741
+ /**
2742
+ * 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'.
2743
+ */
2744
+ capability_id?: string;
2745
+ /**
2746
+ * 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.
2747
+ */
2748
+ display_name?: string;
2749
+ /**
2750
+ * 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`.
2751
+ */
2752
+ applies_to_channels?: MediaChannel[];
2753
+ /**
2754
+ * 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.
2755
+ *
2756
+ * **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.
2757
+ */
2758
+ seller_preference?: 'preferred' | 'accepted' | 'discouraged';
2759
+ /**
2760
+ * 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.
2761
+ */
2762
+ canonical_formats_only?: boolean;
2763
+ /**
2764
+ * 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.
2765
+ *
2766
+ * 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.
2767
+ *
2768
+ * Replaces the earlier `runtime_status` enum (`stable | preview | declared_only`) — same semantic ('use with caution') without the cognitive overhead of two stability axes.
2769
+ */
2770
+ experimental?: boolean;
2771
+ /**
2772
+ * 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.
2773
+ */
2774
+ format_shape?: string;
2775
+ /**
2776
+ * 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.
2777
+ *
2778
+ * 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`.
2779
+ *
2780
+ * **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.
2781
+ *
2782
+ * 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).
2783
+ *
2784
+ * 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.
2785
+ *
2786
+ * **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.
2787
+ *
2788
+ * 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.
2789
+ *
2790
+ * **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.
2791
+ *
2792
+ * **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).
2793
+ *
2794
+ * 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.
2795
+ */
2796
+ v1_format_ref?: FormatReferenceStructuredObject[];
2797
+ format_schema?: PlatformExtensionReference;
2798
+ } & (ImageFormatDeclaration | HTML5FormatDeclaration | DisplayTagFormatDeclaration | ImageCarouselFormatDeclaration | HostedVideoFormatDeclaration | VASTVideoFormatDeclaration | HostedAudioFormatDeclaration | DAASTAudioFormatDeclaration | SponsoredPlacementFormatDeclaration | NativeInFeedFormatDeclaration | ResponsiveCreativeFormatDeclaration | AgentPlacementFormatDeclaration | CustomFormatDeclaration);
2799
+
2800
+ /**
2801
+ * Identifier for a publisher property. Must be lowercase alphanumeric with underscores only.
2802
+ * @pattern ^[a-z0-9_]+$
2803
+ */
2804
+ export type PropertyID = string;
2805
+
2806
+ /**
2807
+ * 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.
2808
+ */
2809
+ export interface PushNotificationConfig {
2810
+ /**
2811
+ * 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).
2812
+ */
2813
+ url: string;
2814
+ /**
2815
+ * 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`.
2816
+ * @minLength 1
2817
+ * @maxLength 255
2818
+ * @pattern ^[A-Za-z0-9_.:-]{1,255}$
2819
+ */
2820
+ operation_id?: string;
2821
+ /**
2822
+ * 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.
2823
+ * @minLength 16
2824
+ * @maxLength 4096
2825
+ */
2826
+ token?: string;
2827
+ /**
2828
+ * 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).
2829
+ */
2830
+ authentication?: {
2831
+ /**
2832
+ * 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.
2833
+ */
2834
+ schemes: AuthenticationScheme[];
2835
+ /**
2836
+ * 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.
2837
+ * @minLength 32
2838
+ */
2839
+ credentials: string;
2840
+ };
2841
+ }
2842
+
2843
+ /**
2844
+ * Repeatable asset group (for carousels, slideshows, playlists, etc.)
2845
+ */
2846
+ export interface RepeatableGroupAsset {
2847
+ /**
2848
+ * Discriminator indicating this is a repeatable asset group
2849
+ */
2850
+ item_type: 'repeatable_group';
2851
+ /**
2852
+ * Identifier for this asset group (e.g., 'product', 'slide', 'card')
2853
+ */
2854
+ asset_group_id: string;
2855
+ /**
2856
+ * Whether this asset group is required. If true, at least min_count repetitions must be provided.
2857
+ */
2858
+ required: boolean;
2859
+ /**
2860
+ * Minimum number of repetitions required (if group is required) or allowed (if optional)
2861
+ * @minimum 0
2862
+ */
2863
+ min_count: number;
2864
+ /**
2865
+ * Maximum number of repetitions allowed
2866
+ * @minimum 1
2867
+ */
2868
+ max_count: number;
2869
+ /**
2870
+ * How the platform uses repetitions of this group. 'sequential' means all items display in order (carousels, playlists). 'optimize' means the platform selects the best-performing combination from alternatives (asset group optimization like Meta Advantage+ or Google Pmax).
2871
+ */
2872
+ selection_mode?: 'sequential' | 'optimize';
2873
+ /**
2874
+ * Assets within each repetition of this group
2875
+ */
2876
+ assets: GroupAssetSlot[];
2877
+ }
2878
+
2879
+ export type Responsive = {
2880
+ [k: string]: unknown | undefined;
2881
+ };
2882
+
2883
+ export interface ResponsiveCreativeFormatDeclaration {
2884
+ format_kind: 'responsive_creative';
2885
+ params: CanonicalFormatResponsiveCreative;
2886
+ }
2887
+
2888
+ /**
2889
+ * Video scan method. Modern digital delivery requires progressive scan; interlaced is retained for broadcast legacy content.
2890
+ */
2891
+ export type ScanType = 'progressive' | 'interlaced';
2892
+
2893
+ /**
2894
+ * 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.
2895
+ */
2896
+ export type SizeModeMutex = Fixed | MultiSize | Responsive | None;
2897
+
2898
+ export interface SponsoredPlacementFormatDeclaration {
2899
+ format_kind: 'sponsored_placement';
2900
+ params: CanonicalFormatSponsoredPlacementRetailMediaCatalogDriven;
2901
+ }
2902
+
2903
+ /**
2904
+ * 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.
2905
+ */
2906
+ export type TaskStatus = 'submitted' | 'working' | 'input-required' | 'completed' | 'canceled' | 'failed' | 'rejected' | 'auth-required' | 'unknown';
2907
+
2908
+ /**
2909
+ * Requirements for text creative assets such as headlines, body copy, and CTAs.
2910
+ */
2911
+ export interface TextAssetRequirements {
2912
+ /**
2913
+ * Minimum character length
2914
+ * @minimum 0
2915
+ */
2916
+ min_length?: number;
2917
+ /**
2918
+ * Maximum character length
2919
+ * @minimum 1
2920
+ */
2921
+ max_length?: number;
2922
+ /**
2923
+ * Minimum number of lines
2924
+ * @minimum 1
2925
+ */
2926
+ min_lines?: number;
2927
+ /**
2928
+ * Maximum number of lines
2929
+ * @minimum 1
2930
+ */
2931
+ max_lines?: number;
2932
+ /**
2933
+ * Regex pattern defining allowed characters (e.g., '^[a-zA-Z0-9 .,!?-]+$')
2934
+ */
2935
+ character_pattern?: string;
2936
+ /**
2937
+ * List of prohibited words or phrases
2938
+ */
2939
+ prohibited_terms?: string[];
2940
+ /**
2941
+ * Closed set of permitted string values for this text slot. When present, a conformant implementation MUST reject any submitted content not in this list with `CREATIVE_VALUE_NOT_ALLOWED` (echoing the offending field path in `error.field` and the allowed list in `error.details.allowed_values`). Matching is case-sensitive; producers MUST supply exact casing. If the submitted value contains unresolved template tokens (e.g., {{product_name}}), validation against allowed_values MUST be deferred until interpolation is complete. All declared constraints (allowed_values, character_pattern, max_length, etc.) are conjunctive — submitted content must satisfy every applicable constraint simultaneously.
2942
+ */
2943
+ allowed_values?: string[];
2944
+ }
2945
+
2946
+ /**
2947
+ * Requirements for URL assets such as click-through URLs, tracking pixels, and landing pages.
2948
+ */
2949
+ export interface URLAssetRequirements {
2950
+ /**
2951
+ * Purpose this URL slot serves in the format — distinct from `url_type` on the manifest-side asset (which declares the receiver's invocation mechanism). A slot can be `click_tracker` (purpose) and accept a `tracker_pixel` (mechanism) URL, or `clickthrough` (purpose) and accept a `clickthrough` (mechanism) URL. Complements `asset_role` (human-readable label) by providing a machine-readable enum and serves as the receiver's fallback signal when a manifest URL asset omits `url_type`.
2952
+ */
2953
+ role?: 'clickthrough' | 'landing_page' | 'impression_tracker' | 'click_tracker' | 'viewability_tracker' | 'third_party_tracker';
2954
+ /**
2955
+ * Allowed URL protocols. HTTPS is recommended for all ad URLs.
2956
+ */
2957
+ protocols?: ('https' | 'http')[];
2958
+ /**
2959
+ * List of allowed domains for the URL
2960
+ */
2961
+ allowed_domains?: string[];
2962
+ /**
2963
+ * Maximum URL length in characters
2964
+ * @minimum 1
2965
+ */
2966
+ max_length?: number;
2967
+ /**
2968
+ * Whether the URL supports macro substitution (e.g., ${CACHEBUSTER})
2969
+ */
2970
+ macro_support?: boolean;
2971
+ }
2972
+
2973
+ /**
2974
+ * Standardized macro placeholders for dynamic value substitution in creative tracking URLs. Macros are replaced with actual values at impression time. See docs/creative/universal-macros.mdx for detailed documentation.
2975
+ */
2976
+ export type UniversalMacro = 'MEDIA_BUY_ID' | 'PACKAGE_ID' | 'CREATIVE_ID' | 'CACHEBUSTER' | 'TIMESTAMP' | 'CLICK_URL' | 'GDPR' | 'GDPR_CONSENT' | 'US_PRIVACY' | 'GPP_STRING' | 'GPP_SID' | 'IP_ADDRESS' | 'LIMIT_AD_TRACKING' | 'DEVICE_TYPE' | 'OS' | 'OS_VERSION' | 'DEVICE_MAKE' | 'DEVICE_MODEL' | 'USER_AGENT' | 'APP_BUNDLE' | 'APP_NAME' | 'COUNTRY' | 'REGION' | 'CITY' | 'ZIP' | 'DMA' | 'LAT' | 'LONG' | 'DEVICE_ID' | 'DEVICE_ID_TYPE' | 'DOMAIN' | 'PAGE_URL' | 'REFERRER' | 'KEYWORDS' | 'PLACEMENT_ID' | 'FOLD_POSITION' | 'AD_WIDTH' | 'AD_HEIGHT' | 'VIDEO_ID' | 'VIDEO_TITLE' | 'VIDEO_DURATION' | 'VIDEO_CATEGORY' | 'CONTENT_GENRE' | 'CONTENT_RATING' | 'PLAYER_WIDTH' | 'PLAYER_HEIGHT' | 'POD_POSITION' | 'POD_SIZE' | 'AD_BREAK_ID' | 'STATION_ID' | 'COLLECTION_NAME' | 'INSTALLMENT_ID' | 'AUDIO_DURATION' | 'TMPX' | 'AXEM' | 'CATALOG_ID' | 'SKU' | 'GTIN' | 'OFFERING_ID' | 'JOB_ID' | 'HOTEL_ID' | 'FLIGHT_ID' | 'VEHICLE_ID' | 'LISTING_ID' | 'STORE_ID' | 'PROGRAM_ID' | 'DESTINATION_ID' | 'CREATIVE_VARIANT_ID' | 'APP_ITEM_ID';
2977
+
2978
+ /**
2979
+ * Requirements for VAST (Video Ad Serving Template) creative assets.
2980
+ */
2981
+ export interface VASTAssetRequirements {
2982
+ /**
2983
+ * Required VAST version
2984
+ */
2985
+ vast_version?: '2.0' | '3.0' | '4.0' | '4.1' | '4.2';
2986
+ }
2987
+
2988
+ export interface VASTVideoFormatDeclaration {
2989
+ format_kind: 'video_vast';
2990
+ params: CanonicalFormatVASTVideo;
2991
+ }
2992
+
2993
+ /**
2994
+ * Pricing model for a vendor service. Discriminated by model: 'cpm' (fixed CPM), 'percent_of_media' (percentage of spend with optional CPM cap), 'flat_fee' (fixed charge per reporting period), 'per_unit' (fixed price per unit of work), or 'custom' (escape hatch for models not covered by the enumerated forms — requires a description and structured metadata).
2995
+ */
2996
+ export type VendorPricing = CpmPricing | PercentOfMediaPricing | FlatFeePricing | PerUnitPricing | CustomPricing;
2997
+
2998
+ /**
2999
+ * A pricing option offered by a vendor agent (signals, creative, governance). Combines pricing_option_id with the pricing model fields. Pass pricing_option_id in report_usage for billing verification. All vendor discovery responses return pricing_options as an array — vendors may offer multiple options (volume tiers, context-specific rates, different models per product line).
3000
+ */
3001
+ export type VendorPricingOption = {
3002
+ /**
3003
+ * Opaque identifier for this pricing option, unique within the vendor agent. Pass this in report_usage to identify which pricing option was applied.
3004
+ */
3005
+ pricing_option_id: string;
3006
+ } & VendorPricing;
3007
+
3008
+ /**
3009
+ * Requirements for video creative assets. These define the technical constraints for video files.
3010
+ */
3011
+ export interface VideoAssetRequirements {
3012
+ /**
3013
+ * Minimum width in pixels
3014
+ * @minimum 1
3015
+ */
3016
+ min_width?: number;
3017
+ /**
3018
+ * Maximum width in pixels
3019
+ * @minimum 1
3020
+ */
3021
+ max_width?: number;
3022
+ /**
3023
+ * Minimum height in pixels
3024
+ * @minimum 1
3025
+ */
3026
+ min_height?: number;
3027
+ /**
3028
+ * Maximum height in pixels
3029
+ * @minimum 1
3030
+ */
3031
+ max_height?: number;
3032
+ /**
3033
+ * Required aspect ratio (e.g., '16:9', '9:16')
3034
+ * @pattern ^\d+:\d+$
3035
+ */
3036
+ aspect_ratio?: string;
3037
+ /**
3038
+ * Minimum duration in milliseconds
3039
+ * @minimum 1
3040
+ */
3041
+ min_duration_ms?: number;
3042
+ /**
3043
+ * Maximum duration in milliseconds
3044
+ * @minimum 1
3045
+ */
3046
+ max_duration_ms?: number;
3047
+ /**
3048
+ * Accepted video container formats
3049
+ */
3050
+ containers?: ('mp4' | 'webm' | 'mov' | 'avi' | 'mkv')[];
3051
+ /**
3052
+ * Accepted video codecs
3053
+ */
3054
+ codecs?: ('h264' | 'h265' | 'vp8' | 'vp9' | 'av1' | 'prores')[];
3055
+ /**
3056
+ * Maximum file size in kilobytes
3057
+ * @minimum 1
3058
+ */
3059
+ max_file_size_kb?: number;
3060
+ /**
3061
+ * Minimum video bitrate in kilobits per second
3062
+ * @minimum 1
3063
+ */
3064
+ min_bitrate_kbps?: number;
3065
+ /**
3066
+ * Maximum video bitrate in kilobits per second
3067
+ * @minimum 1
3068
+ */
3069
+ max_bitrate_kbps?: number;
3070
+ /**
3071
+ * Accepted frame rates in frames per second (e.g., [24, 30, 60])
3072
+ */
3073
+ frame_rates?: number[];
3074
+ /**
3075
+ * Whether the video must include an audio track
3076
+ */
3077
+ audio_required?: boolean;
3078
+ frame_rate_type?: FrameRateType;
3079
+ scan_type?: ScanType;
3080
+ gop_type?: GOPType;
3081
+ /**
3082
+ * Minimum keyframe interval in seconds
3083
+ * @minimum 0
3084
+ */
3085
+ min_gop_interval_seconds?: number;
3086
+ /**
3087
+ * Maximum keyframe interval in seconds. SSAI typically requires 1-2 second intervals.
3088
+ * @minimum 0
3089
+ */
3090
+ max_gop_interval_seconds?: number;
3091
+ moov_atom_position?: MoovAtomPosition;
3092
+ /**
3093
+ * Accepted audio codecs (e.g., ['aac', 'pcm', 'ac3'])
3094
+ */
3095
+ audio_codecs?: ('aac' | 'pcm' | 'ac3' | 'eac3' | 'mp3' | 'opus' | 'vorbis' | 'flac')[];
3096
+ /**
3097
+ * Accepted audio sample rates in Hz (e.g., [44100, 48000])
3098
+ */
3099
+ audio_sample_rates?: number[];
3100
+ /**
3101
+ * Accepted audio channel configurations
3102
+ */
3103
+ audio_channels?: AudioChannelLayout[];
3104
+ /**
3105
+ * Target integrated loudness in LUFS (e.g., -24 for broadcast, -16 for streaming)
3106
+ */
3107
+ loudness_lufs?: number;
3108
+ /**
3109
+ * Acceptable deviation from loudness_lufs target in dB (e.g., 2 means -22 to -26 LUFS for a -24 target)
3110
+ * @minimum 0
3111
+ */
3112
+ loudness_tolerance_db?: number;
3113
+ /**
3114
+ * Maximum true peak level in dBFS (e.g., -2 for broadcast)
3115
+ */
3116
+ true_peak_dbfs?: number;
3117
+ }
3118
+
3119
+ /**
3120
+ * Filter to formats that meet at least this WCAG conformance level (A < AA < AAA)
3121
+ */
3122
+ export type WCAGLevel = 'A' | 'AA' | 'AAA';
3123
+
3124
+ /**
3125
+ * Requirements for webhook creative assets.
3126
+ */
3127
+ export interface WebhookAssetRequirements {
3128
+ /**
3129
+ * Allowed HTTP methods
3130
+ */
3131
+ methods?: ('GET' | 'POST')[];
3132
+ }