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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +12 -0
  2. package/dist/lib/conformance/oracle.d.ts.map +1 -1
  3. package/dist/lib/conformance/oracle.js +8 -1
  4. package/dist/lib/conformance/oracle.js.map +1 -1
  5. package/dist/lib/conformance/schemaArbitrary.js +135 -9
  6. package/dist/lib/conformance/schemaArbitrary.js.map +1 -1
  7. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  8. package/dist/lib/server/create-adcp-server.d.ts +5 -0
  9. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  10. package/dist/lib/server/create-adcp-server.js +41 -3
  11. package/dist/lib/server/create-adcp-server.js.map +1 -1
  12. package/dist/lib/server/decisioning/capabilities.d.ts +8 -0
  13. package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
  14. package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -1
  15. package/dist/lib/server/decisioning/proposal/dispatch.js +2 -0
  16. package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -1
  17. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  18. package/dist/lib/server/decisioning/runtime/from-platform.js +14 -1
  19. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  20. package/dist/lib/server/responses.d.ts +1 -1
  21. package/dist/lib/server/responses.d.ts.map +1 -1
  22. package/dist/lib/server/responses.js +5 -2
  23. package/dist/lib/server/responses.js.map +1 -1
  24. package/dist/lib/signing/types.d.ts +6 -0
  25. package/dist/lib/signing/types.d.ts.map +1 -1
  26. package/dist/lib/signing/types.js.map +1 -1
  27. package/dist/lib/signing/verifier.d.ts.map +1 -1
  28. package/dist/lib/signing/verifier.js +33 -4
  29. package/dist/lib/signing/verifier.js.map +1 -1
  30. package/dist/lib/testing/storyboard/compliance.d.ts +1 -0
  31. package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
  32. package/dist/lib/testing/storyboard/compliance.js +8 -2
  33. package/dist/lib/testing/storyboard/compliance.js.map +1 -1
  34. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  35. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  36. package/dist/lib/testing/storyboard/index.js +3 -2
  37. package/dist/lib/testing/storyboard/index.js.map +1 -1
  38. package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
  39. package/dist/lib/testing/storyboard/probes.js +3 -0
  40. package/dist/lib/testing/storyboard/probes.js.map +1 -1
  41. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  42. package/dist/lib/testing/storyboard/runner.js +294 -29
  43. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  44. package/dist/lib/testing/storyboard/types.d.ts +59 -0
  45. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  46. package/dist/lib/testing/storyboard/types.js.map +1 -1
  47. package/dist/lib/testing/storyboard/validations.d.ts +4 -3
  48. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
  49. package/dist/lib/testing/storyboard/validations.js +26 -2
  50. package/dist/lib/testing/storyboard/validations.js.map +1 -1
  51. package/dist/lib/types/activate-signal.d.ts +647 -0
  52. package/dist/lib/types/build-creative.d.ts +2105 -0
  53. package/dist/lib/types/calibrate-content.d.ts +675 -0
  54. package/dist/lib/types/check-governance.d.ts +619 -0
  55. package/dist/lib/types/comply-test-controller.d.ts +8428 -0
  56. package/dist/lib/types/core.generated.d.ts +180 -252
  57. package/dist/lib/types/core.generated.d.ts.map +1 -1
  58. package/dist/lib/types/core.generated.js +1 -1
  59. package/dist/lib/types/create-collection-list.d.ts +693 -0
  60. package/dist/lib/types/create-content-standards.d.ts +830 -0
  61. package/dist/lib/types/create-media-buy.d.ts +3374 -0
  62. package/dist/lib/types/create-property-list.d.ts +836 -0
  63. package/dist/lib/types/delete-collection-list.d.ts +497 -0
  64. package/dist/lib/types/delete-property-list.d.ts +497 -0
  65. package/dist/lib/types/get-account-financials.d.ts +624 -0
  66. package/dist/lib/types/get-adcp-capabilities.d.ts +2863 -0
  67. package/dist/lib/types/get-collection-list.d.ts +763 -0
  68. package/dist/lib/types/get-content-standards.d.ts +919 -0
  69. package/dist/lib/types/get-creative-delivery.d.ts +2219 -0
  70. package/dist/lib/types/get-creative-features.d.ts +1736 -0
  71. package/dist/lib/types/get-media-buy-artifacts.d.ts +864 -0
  72. package/dist/lib/types/get-media-buys.d.ts +1670 -0
  73. package/dist/lib/types/get-plan-audit-logs.d.ts +455 -0
  74. package/dist/lib/types/get-products.d.ts +4935 -0
  75. package/dist/lib/types/get-property-list.d.ts +874 -0
  76. package/dist/lib/types/get-signals.d.ts +986 -0
  77. package/dist/lib/types/list-accounts.d.ts +851 -0
  78. package/dist/lib/types/list-content-standards.d.ts +975 -0
  79. package/dist/lib/types/list-creative-formats.d.ts +3132 -0
  80. package/dist/lib/types/list-creatives.d.ts +2390 -0
  81. package/dist/lib/types/list-property-lists.d.ts +855 -0
  82. package/dist/lib/types/log-event.d.ts +373 -0
  83. package/dist/lib/types/per-tool-index.json +391 -0
  84. package/dist/lib/types/preview-creative.d.ts +1981 -0
  85. package/dist/lib/types/provide-performance-feedback.d.ts +218 -0
  86. package/dist/lib/types/report-plan-outcome.d.ts +433 -0
  87. package/dist/lib/types/report-usage.d.ts +579 -0
  88. package/dist/lib/types/schemas.generated.d.ts +127279 -125067
  89. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  90. package/dist/lib/types/schemas.generated.js +221 -293
  91. package/dist/lib/types/schemas.generated.js.map +1 -1
  92. package/dist/lib/types/si-get-offering.d.ts +259 -0
  93. package/dist/lib/types/si-initiate-session.d.ts +372 -0
  94. package/dist/lib/types/si-send-message.d.ts +300 -0
  95. package/dist/lib/types/si-terminate-session.d.ts +213 -0
  96. package/dist/lib/types/sync-accounts.d.ts +856 -0
  97. package/dist/lib/types/sync-audiences.d.ts +707 -0
  98. package/dist/lib/types/sync-catalogs.d.ts +766 -0
  99. package/dist/lib/types/sync-creatives.d.ts +2134 -0
  100. package/dist/lib/types/sync-event-sources.d.ts +665 -0
  101. package/dist/lib/types/sync-governance.d.ts +558 -0
  102. package/dist/lib/types/sync-plans.d.ts +979 -0
  103. package/dist/lib/types/update-collection-list.d.ts +697 -0
  104. package/dist/lib/types/update-content-standards.d.ts +847 -0
  105. package/dist/lib/types/update-media-buy.d.ts +3047 -0
  106. package/dist/lib/types/update-property-list.d.ts +840 -0
  107. package/dist/lib/types/validate-content-delivery.d.ts +722 -0
  108. package/dist/lib/types/validate-input.d.ts +1683 -0
  109. package/dist/lib/utils/response-schemas.js +1 -1
  110. package/dist/lib/utils/response-schemas.js.map +1 -1
  111. package/dist/lib/utils/response-unwrapper.d.ts.map +1 -1
  112. package/dist/lib/utils/response-unwrapper.js +18 -3
  113. package/dist/lib/utils/response-unwrapper.js.map +1 -1
  114. package/dist/lib/version.d.ts +3 -3
  115. package/dist/lib/version.js +3 -3
  116. package/examples/error-compliant-server.ts +1 -1
  117. package/examples/hello_seller_adapter_guaranteed.ts +8 -3
  118. package/examples/hello_seller_adapter_multi_tenant.ts +27 -23
  119. package/examples/hello_seller_adapter_non_guaranteed.ts +7 -3
  120. package/examples/hello_seller_adapter_proposal_mode.ts +22 -6
  121. package/examples/hello_signals_adapter_marketplace.ts +34 -3
  122. package/package.json +9 -2
@@ -0,0 +1,2219 @@
1
+ // AUTO-GENERATED — DO NOT EDIT.
2
+ // Per-tool .d.ts slice for `get_creative_delivery`. 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 retrieving creative delivery data including variant-level metrics from a creative agent. At least one scoping filter (media_buy_ids or creative_ids) is required.
13
+ */
14
+ export type GetCreativeDeliveryRequest = {
15
+ [k: string]: unknown | undefined;
16
+ } & {
17
+ /**
18
+ * 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.
19
+ */
20
+ adcp_version?: string;
21
+ /**
22
+ * 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.
23
+ */
24
+ adcp_major_version?: number;
25
+ account?: AccountReference;
26
+ /**
27
+ * Filter to specific media buys by publisher ID. If omitted, returns creative delivery across all matching media buys.
28
+ */
29
+ media_buy_ids?: string[];
30
+ /**
31
+ * Filter to specific creatives by ID. If omitted, returns delivery for all creatives matching the other filters.
32
+ */
33
+ creative_ids?: string[];
34
+ /**
35
+ * Start date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.
36
+ * @pattern ^\d{4}-\d{2}-\d{2}$
37
+ */
38
+ start_date?: string;
39
+ /**
40
+ * End date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.
41
+ * @pattern ^\d{4}-\d{2}-\d{2}$
42
+ */
43
+ end_date?: string;
44
+ /**
45
+ * Maximum number of variants to return per creative. When omitted, the agent returns all variants. Use this to limit response size for generative creatives that may produce large numbers of variants.
46
+ * @minimum 1
47
+ */
48
+ max_variants?: number;
49
+ pagination?: PaginationRequest;
50
+ context?: ContextObject;
51
+ ext?: ExtensionObject;
52
+ };
53
+
54
+ /**
55
+ * Response payload for get_creative_delivery task. Returns creative delivery data with variant-level breakdowns including manifests and metrics.
56
+ */
57
+ export interface GetCreativeDeliveryResponse {
58
+ /**
59
+ * 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).
60
+ */
61
+ context_id?: string;
62
+ context?: ContextObject;
63
+ /**
64
+ * Unique identifier for tracking asynchronous operations. Present when a task requires extended processing time. Used to query task status and retrieve results when complete.
65
+ */
66
+ task_id?: string;
67
+ status: TaskStatus;
68
+ /**
69
+ * 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.
70
+ */
71
+ message?: string;
72
+ /**
73
+ * ISO 8601 timestamp when the response was generated. Useful for debugging, logging, cache validation, and tracking async operation progress.
74
+ */
75
+ timestamp?: string;
76
+ /**
77
+ * 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.
78
+ */
79
+ replayed?: boolean;
80
+ adcp_error?: Error;
81
+ push_notification_config?: PushNotificationConfig;
82
+ /**
83
+ * 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.
84
+ *
85
+ * 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.
86
+ *
87
+ * This is the primary correlation key for audit and reporting across the governance lifecycle.
88
+ */
89
+ governance_context?: string;
90
+ /**
91
+ * 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.
92
+ */
93
+ payload?: {};
94
+ /**
95
+ * 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.
96
+ */
97
+ adcp_version?: string;
98
+ /**
99
+ * 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.
100
+ */
101
+ adcp_major_version?: number;
102
+ /**
103
+ * Account identifier. Present when the response spans or is scoped to a specific account.
104
+ */
105
+ account_id?: string;
106
+ /**
107
+ * Publisher's media buy identifier. Present when the request was scoped to a single media buy.
108
+ */
109
+ media_buy_id?: string;
110
+ /**
111
+ * ISO 4217 currency code for monetary values in this response (e.g., 'USD', 'EUR')
112
+ * @pattern ^[A-Z]{3}$
113
+ */
114
+ currency: string;
115
+ /**
116
+ * Date range for the report.
117
+ */
118
+ reporting_period: {
119
+ /**
120
+ * ISO 8601 start timestamp
121
+ * @format date-time
122
+ */
123
+ start: string;
124
+ /**
125
+ * ISO 8601 end timestamp
126
+ * @format date-time
127
+ */
128
+ end: string;
129
+ /**
130
+ * IANA timezone identifier for the reporting period (e.g., 'America/New_York', 'UTC'). Platforms report in their native timezone.
131
+ */
132
+ timezone?: string;
133
+ };
134
+ /**
135
+ * Creative delivery data with variant breakdowns
136
+ */
137
+ creatives: {
138
+ /**
139
+ * Creative identifier
140
+ */
141
+ creative_id: string;
142
+ /**
143
+ * Publisher's media buy identifier for this creative. Present when the request spanned multiple media buys, so the buyer can correlate each creative to its media buy.
144
+ */
145
+ media_buy_id?: string;
146
+ format_id?: FormatReferenceStructuredObject;
147
+ totals?: DeliveryMetrics;
148
+ /**
149
+ * Total number of variants for this creative. When max_variants was specified in the request, this may exceed the number of items in the variants array.
150
+ * @minimum 0
151
+ */
152
+ variant_count?: number;
153
+ /**
154
+ * Variant-level delivery breakdown. Each variant includes the rendered manifest and delivery metrics. For standard creatives, contains a single variant. For asset group optimization, one per combination. For generative creative, one per generated execution. Empty when a creative has no variants yet.
155
+ */
156
+ variants: CreativeVariant[];
157
+ }[];
158
+ /**
159
+ * Pagination information. Present when the request included pagination parameters. **Note:** `get_creative_delivery` uses page-based pagination (`limit`/`offset`) for historical reasons, distinct from the cursor-based [`PaginationResponse`](/schemas/v3/core/pagination-response.json) used by `list_*` tools. Field naming aligned with `PaginationResponse.total_count` in 3.1; the legacy `total` field is retained as a deprecated alias until 4.0. Sellers MUST populate both fields identically; buyers SHOULD prefer `total_count` (the canonical name) and ignore `total` if both are present.
160
+ */
161
+ pagination?: {
162
+ /**
163
+ * Maximum number of creatives requested
164
+ * @minimum 1
165
+ */
166
+ limit: number;
167
+ /**
168
+ * Number of creatives skipped
169
+ * @minimum 0
170
+ */
171
+ offset: number;
172
+ /**
173
+ * Whether more creatives are available beyond this page
174
+ */
175
+ has_more: boolean;
176
+ /**
177
+ * Total number of creatives matching the request filters. Canonical field name (matches `PaginationResponse.total_count`). Sellers SHOULD populate this and the deprecated `total` field identically until 4.0; buyers SHOULD prefer this field.
178
+ * @minimum 0
179
+ */
180
+ total_count?: number;
181
+ /**
182
+ * @deprecated
183
+ * **Deprecated** — use `total_count` instead. Retained as a legacy alias for 3.x backward compatibility; removed in AdCP 4.0. Sellers populating this field MUST also populate `total_count` with the same value.
184
+ * @minimum 0
185
+ */
186
+ total?: number;
187
+ };
188
+ /**
189
+ * Task-specific errors and warnings
190
+ */
191
+ errors?: Error[];
192
+ ext?: ExtensionObject;
193
+ }
194
+
195
+ /**
196
+ * Account for product lookup. Returns products with pricing specific to this account's rate card.
197
+ */
198
+ export type AccountReference = {
199
+ /**
200
+ * Seller-assigned account identifier (from sync_accounts or list_accounts)
201
+ */
202
+ account_id: string;
203
+ } | {
204
+ brand: BrandReference;
205
+ /**
206
+ * Domain of the entity operating on the brand's behalf. When the brand operates directly, this is the brand's domain.
207
+ * @pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$
208
+ */
209
+ operator: string;
210
+ /**
211
+ * When true, references the sandbox account for this brand/operator pair. Defaults to false (production account).
212
+ */
213
+ sandbox?: boolean;
214
+ };
215
+
216
+ /**
217
+ * Where the conversion event originated
218
+ */
219
+ export type ActionSource = 'website' | 'app' | 'offline' | 'phone_call' | 'chat' | 'email' | 'in_store' | 'system_generated' | 'other';
220
+
221
+ /**
222
+ * Canonical union of all asset variant schemas. Referenced from creative-asset.json and creative-manifest.json to ensure a single named type is emitted by schema-to-TypeScript tooling. Add new asset types here and to the creative/asset-types registry.
223
+ */
224
+ export type AssetVariant = ImageAsset | VideoAsset | AudioAsset | VASTAsset | TextAsset | URLAsset | HTMLAsset | JavaScriptAsset | ZipAsset | WebhookAsset | CSSAsset | DAASTAsset | MarkdownAsset | BriefAsset | CatalogAsset | CardAsset;
225
+
226
+ /**
227
+ * Audio asset with URL and technical specifications
228
+ */
229
+ export interface AudioAsset {
230
+ /**
231
+ * Discriminator identifying this as an audio asset. See /schemas/creative/asset-types for the registry.
232
+ */
233
+ asset_type: 'audio';
234
+ /**
235
+ * URL to the audio asset
236
+ */
237
+ url: string;
238
+ /**
239
+ * Audio duration in milliseconds
240
+ * @minimum 0
241
+ */
242
+ duration_ms?: number;
243
+ /**
244
+ * File size in bytes
245
+ * @minimum 1
246
+ */
247
+ file_size_bytes?: number;
248
+ /**
249
+ * Audio container/file format (mp3, m4a, aac, wav, ogg, flac, etc.)
250
+ */
251
+ container_format?: string;
252
+ /**
253
+ * Audio codec used (aac, aac_lc, he_aac, pcm, mp3, vorbis, opus, flac, ac3, eac3, etc.)
254
+ */
255
+ codec?: string;
256
+ /**
257
+ * Sampling rate in Hz (e.g., 44100, 48000, 96000)
258
+ */
259
+ sampling_rate_hz?: number;
260
+ channels?: AudioChannelLayout;
261
+ /**
262
+ * Bit depth
263
+ */
264
+ bit_depth?: 16 | 24 | 32;
265
+ /**
266
+ * Bitrate in kilobits per second
267
+ * @minimum 1
268
+ */
269
+ bitrate_kbps?: number;
270
+ /**
271
+ * Integrated loudness in LUFS
272
+ */
273
+ loudness_lufs?: number;
274
+ /**
275
+ * True peak level in dBFS
276
+ */
277
+ true_peak_dbfs?: number;
278
+ /**
279
+ * URL to text transcript of the audio content
280
+ */
281
+ transcript_url?: string;
282
+ provenance?: Provenance;
283
+ }
284
+
285
+ /**
286
+ * Audio channel configuration
287
+ */
288
+ export type AudioChannelLayout = 'mono' | 'stereo' | '5.1' | '7.1';
289
+
290
+ /**
291
+ * 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.
292
+ */
293
+ export type AuthenticationScheme = 'Bearer' | 'HMAC-SHA256';
294
+
295
+ /**
296
+ * Brand identifier within the house portfolio. Optional for single-brand domains.
297
+ */
298
+ export type BrandID = string;
299
+
300
+ /**
301
+ * Brand reference for product discovery context. Resolved to full brand identity at execution time.
302
+ */
303
+ export interface BrandReference {
304
+ /**
305
+ * Domain where /.well-known/brand.json is hosted, or the brand's operating domain
306
+ * @pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$
307
+ */
308
+ domain: string;
309
+ brand_id?: BrandID;
310
+ /**
311
+ * Inline override for the brand's industries. Useful when the caller cannot modify the brand's canonical brand.json but needs to declare industries for governance (e.g., Annex III vertical detection). brand.json remains the canonical source; when omitted here, governance agents SHOULD resolve from brand.json.
312
+ */
313
+ industries?: string[];
314
+ /**
315
+ * Inline override for the brand's contestation contact point. Useful when the operator does not control brand.json but needs to discharge Art 22(3) for this plan. brand.json is canonical; when omitted, governance agents resolve brand → house → missing.
316
+ */
317
+ data_subject_contestation?: {
318
+ [k: string]: unknown | undefined;
319
+ };
320
+ /**
321
+ * Inline override for brand-kit fields normally resolved from `/.well-known/brand.json` on `domain` (logo, colors, voice, tagline). Use when brand.json is missing, stale, or inappropriate for this specific call — e.g., a campaign-scoped tagline, a co-branded creative, a freshly-rebranded color palette the brand.json hasn't shipped yet. Same inline-override pattern as `industries` and `data_subject_contestation` above: brand.json is canonical, the override is per-call. Adopters needing to override fields outside this subset (`voice_attributes`, `prohibited_terms`, etc.) MUST publish a different brand.json and reference it via a different `domain` — the inline override is intentionally narrow to a small high-traffic subset.
322
+ *
323
+ * **Merge semantics (normative).** The merge is **field-level**, not whole-object replacement. Each field within `brand_kit_override` (`logo`, `colors`, `voice`, `tagline`) is evaluated independently — when a field is present on the override the override value applies; when a field is absent the brand.json value applies (or is absent if brand.json doesn't carry one either). For composite fields (`colors.primary`, `colors.secondary`, `colors.accent`), the merge is one level deeper: each color slot is evaluated independently — a producer can override `colors.primary` while still inheriting `colors.secondary` from brand.json. SDKs MUST NOT treat a present `brand_kit_override.colors` as wiping the brand.json `colors` block entirely; only the per-slot fields present in the override take precedence. Without this rule, a partial-override semantics would diverge across SDKs and produce inconsistent rendering for the same payload.
324
+ */
325
+ brand_kit_override?: {
326
+ logo?: ImageAsset;
327
+ /**
328
+ * Override brand colors (hex strings).
329
+ */
330
+ colors?: {
331
+ /**
332
+ * @pattern ^#[0-9a-fA-F]{6}$
333
+ */
334
+ primary?: string;
335
+ /**
336
+ * @pattern ^#[0-9a-fA-F]{6}$
337
+ */
338
+ secondary?: string;
339
+ /**
340
+ * @pattern ^#[0-9a-fA-F]{6}$
341
+ */
342
+ accent?: string;
343
+ };
344
+ /**
345
+ * Override brand-voice description for surface-composed text/audio output.
346
+ */
347
+ voice?: string;
348
+ /**
349
+ * Override tagline.
350
+ */
351
+ tagline?: string;
352
+ };
353
+ }
354
+
355
+ /**
356
+ * Campaign-level creative context as an asset. Carries the creative brief through the manifest so it travels with the creative through regeneration, resizing, and auditing.
357
+ */
358
+ export interface BriefAsset {
359
+ /**
360
+ * Campaign or flight name for identification
361
+ */
362
+ name: string;
363
+ /**
364
+ * Campaign objective that guides creative tone and call-to-action strategy
365
+ */
366
+ objective?: 'awareness' | 'consideration' | 'conversion' | 'retention' | 'engagement';
367
+ /**
368
+ * Desired tone for this campaign, modulating the brand's base tone (e.g., 'playful and festive', 'premium and aspirational')
369
+ */
370
+ tone?: string;
371
+ /**
372
+ * Target audience description for this campaign
373
+ */
374
+ audience?: string;
375
+ /**
376
+ * Creative territory or positioning the campaign should occupy
377
+ */
378
+ territory?: string;
379
+ /**
380
+ * Messaging framework for the campaign
381
+ */
382
+ messaging?: {
383
+ /**
384
+ * Primary headline
385
+ */
386
+ headline?: string;
387
+ /**
388
+ * Supporting tagline or sub-headline
389
+ */
390
+ tagline?: string;
391
+ /**
392
+ * Call-to-action text
393
+ */
394
+ cta?: string;
395
+ /**
396
+ * Key messages to communicate in priority order
397
+ */
398
+ key_messages?: string[];
399
+ };
400
+ /**
401
+ * Visual and strategic reference materials such as mood boards, product shots, example creatives, and strategy documents
402
+ */
403
+ reference_assets?: ReferenceAsset[];
404
+ /**
405
+ * Regulatory and legal compliance requirements for this campaign. Campaign-specific, regional, and product-based — distinct from brand-level disclaimers in brand.json.
406
+ */
407
+ compliance?: {
408
+ /**
409
+ * Disclosures that must appear in creatives for this campaign. Each disclosure specifies the text, where it should appear, and which jurisdictions require it.
410
+ */
411
+ required_disclosures?: {
412
+ /**
413
+ * The disclosure text that must appear in the creative
414
+ */
415
+ text: string;
416
+ position?: DisclosurePosition;
417
+ /**
418
+ * Jurisdictions where this disclosure is required. ISO 3166-1 alpha-2 country codes or ISO 3166-2 subdivision codes (e.g., 'US', 'GB', 'US-NJ', 'CA-QC'). If omitted, the disclosure applies to all jurisdictions in the campaign.
419
+ */
420
+ jurisdictions?: string[];
421
+ /**
422
+ * The regulation or legal authority requiring this disclosure (e.g., 'SEC Rule 156', 'FCA COBS 4.5', 'FDA 21 CFR 202')
423
+ */
424
+ regulation?: string;
425
+ /**
426
+ * Minimum display duration in milliseconds. For video/audio disclosures, how long the disclosure must be visible or audible. For static formats, how long the disclosure must remain on screen before any auto-advance.
427
+ */
428
+ min_duration_ms?: number;
429
+ /**
430
+ * Language of the disclosure text as a BCP 47 language tag (e.g., 'en', 'fr-CA', 'es'). When omitted, the disclosure is assumed to match the creative's language.
431
+ */
432
+ language?: string;
433
+ persistence?: DisclosurePersistence;
434
+ }[];
435
+ /**
436
+ * Claims that must not appear in creatives for this campaign. Creative agents should ensure generated content avoids these claims.
437
+ */
438
+ prohibited_claims?: string[];
439
+ };
440
+ /**
441
+ * Discriminator identifying this as a brief asset. See /schemas/creative/asset-types for the registry.
442
+ */
443
+ asset_type: 'brief';
444
+ }
445
+
446
+ /**
447
+ * C2PA action classification for this watermark
448
+ */
449
+ export type C2PAWatermarkAction = 'c2pa.watermarked.bound' | 'c2pa.watermarked.unbound';
450
+
451
+ /**
452
+ * CSS stylesheet asset
453
+ */
454
+ export interface CSSAsset {
455
+ /**
456
+ * Discriminator identifying this as a CSS asset. See /schemas/creative/asset-types for the registry.
457
+ */
458
+ asset_type: 'css';
459
+ /**
460
+ * CSS content
461
+ */
462
+ content: string;
463
+ /**
464
+ * CSS media query context (e.g., 'screen', 'print')
465
+ */
466
+ media?: string;
467
+ provenance?: Provenance;
468
+ }
469
+
470
+ /**
471
+ * 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`).
472
+ */
473
+ 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';
474
+
475
+ /**
476
+ * A single card in a multi-card creative (image_carousel, future composed carousels). Carries: `media` (an image OR video asset), optional `headline` (short text), optional `description` (longer text), optional `cta` (call-to-action label), optional `landing_page_url` (url asset with `url_type: "clickthrough"`).
477
+ *
478
+ * Covers the multi-card patterns across Meta carousel, Pinterest sponsored pin, Snap Collection, TikTok carousel, and AI-surface result cards. The two-field text shape (`headline` + `description`) reflects how almost every adopter splits short labels from longer copy; Pinterest pin description and Meta per-card description both go in `description`.
479
+ *
480
+ * Used as the array element type for the `cards` slot on image_carousel canonicals. Adopters MUST NOT invent per-card key conventions like `card_0_headline` / `cards.0.headline` — the manifest's `assets.cards` value is an array of card-asset objects, period. Per-card platform extensions (e.g., Meta-specific carousel attributes, Pinterest rich-pin metadata, Snap Collection price tags) attach via the `platform_extensions` field, never via inline non-canonical keys.
481
+ */
482
+ export interface CardAsset {
483
+ /**
484
+ * Discriminator identifying this as a card asset. See /schemas/creative/asset-types for the registry.
485
+ */
486
+ asset_type: 'card';
487
+ /**
488
+ * The card's primary visual asset. Either an `image` or `video` asset, matching the parent format's `allowed_card_media_asset_types` parameter.
489
+ */
490
+ media: ImageAsset | VideoAsset;
491
+ /**
492
+ * Optional per-card short text label (typically 25-40 chars). Length governed by `card_headline_max_chars` on the format declaration. Meta carousel headline, Pinterest pin title, Snap Collection sticker text, TikTok caption-short.
493
+ */
494
+ headline?: string;
495
+ /**
496
+ * Optional per-card longer text (typically 100-500 chars). Distinct from `headline`: `description` is body copy, `headline` is the label. Length governed by `card_description_max_chars` on the format declaration. Meta carousel description, Pinterest pin description, AI-surface result body text, TikTok long caption.
497
+ */
498
+ description?: string;
499
+ /**
500
+ * Optional per-card call-to-action label (e.g., 'SHOP_NOW', 'LEARN_MORE'). When the parent format declares `cta_values` (allowed CTA labels), the per-card `cta` MUST be one of those values. Lets a Meta or TikTok carousel show different CTAs per card.
501
+ */
502
+ cta?: string;
503
+ landing_page_url?: URLAsset;
504
+ /**
505
+ * Per-card platform-specific extensions (URI+digest references). Same hosting model as format-level platform_extensions. Use this for Meta carousel-card attributes, Pinterest pin overrides, etc. — NEVER inline non-canonical keys on the card object directly.
506
+ */
507
+ platform_extensions?: PlatformExtensionReference[];
508
+ provenance?: Provenance;
509
+ }
510
+
511
+ /**
512
+ * A typed data feed as a creative asset. Carries catalog context (products, stores, jobs, etc.) within the manifest's assets map.
513
+ */
514
+ export interface CatalogAsset {
515
+ /**
516
+ * Buyer's identifier for this catalog. Required when syncing via sync_catalogs. When used in creatives, references a previously synced catalog on the account.
517
+ */
518
+ catalog_id?: string;
519
+ /**
520
+ * Human-readable name for this catalog (e.g., 'Summer Products 2025', 'Amsterdam Store Locations').
521
+ */
522
+ name?: string;
523
+ type: CatalogType;
524
+ /**
525
+ * URL to an external catalog feed. The platform fetches and resolves items from this URL. For offering-type catalogs, the feed contains an array of Offering objects. For other types, the feed format is determined by feed_format. When omitted with type 'product', the platform uses its synced copy of the brand's product catalog.
526
+ */
527
+ url?: string;
528
+ feed_format?: FeedFormat;
529
+ update_frequency?: UpdateFrequency;
530
+ /**
531
+ * Inline catalog data. The item schema depends on the catalog type: Offering objects for 'offering', StoreItem for 'store', HotelItem for 'hotel', FlightItem for 'flight', JobItem for 'job', VehicleItem for 'vehicle', RealEstateItem for 'real_estate', EducationItem for 'education', DestinationItem for 'destination', AppItem for 'app', or freeform objects for 'product', 'inventory', and 'promotion'. Mutually exclusive with url — provide one or the other, not both. Implementations should validate items against the type-specific schema.
532
+ */
533
+ items?: {}[];
534
+ /**
535
+ * Filter catalog to specific item IDs. For offering-type catalogs, these are offering_id values. For product-type catalogs, these are SKU identifiers.
536
+ */
537
+ ids?: string[];
538
+ /**
539
+ * Filter product-type catalogs by GTIN identifiers for cross-retailer catalog matching. Accepts standard GTIN formats (GTIN-8, UPC-A/GTIN-12, EAN-13/GTIN-13, GTIN-14). Only applicable when type is 'product'.
540
+ */
541
+ gtins?: string[];
542
+ /**
543
+ * Filter catalog to items with these tags. Tags are matched using OR logic — items matching any tag are included.
544
+ */
545
+ tags?: string[];
546
+ /**
547
+ * Filter catalog to items in this category (e.g., 'beverages/soft-drinks', 'chef-positions').
548
+ */
549
+ category?: string;
550
+ /**
551
+ * Natural language filter for catalog items (e.g., 'all pasta sauces under $5', 'amsterdam vacancies').
552
+ */
553
+ query?: string;
554
+ /**
555
+ * Event types that represent conversions for items in this catalog. Declares what events the platform should attribute to catalog items — e.g., a job catalog converts via submit_application, a product catalog via purchase. The event's content_ids field carries the item IDs that connect back to catalog items. Use content_id_type to declare what identifier type content_ids values represent.
556
+ */
557
+ conversion_events?: EventType[];
558
+ content_id_type?: ContentIDType;
559
+ /**
560
+ * Declarative normalization rules for external feeds. Maps non-standard feed field names, date formats, price encodings, and image URLs to the AdCP catalog item schema. Applied during sync_catalogs ingestion. Supports field renames, named transforms (date, divide, boolean, split), static literal injection, and assignment of image URLs to typed asset pools.
561
+ */
562
+ feed_field_mappings?: CatalogFieldMapping[];
563
+ /**
564
+ * Discriminator identifying this as a catalog asset. See /schemas/creative/asset-types for the registry.
565
+ */
566
+ asset_type: 'catalog';
567
+ }
568
+
569
+ /**
570
+ * Declares how a field in an external feed maps to the AdCP catalog item schema. Used in sync_catalogs feed_field_mappings to normalize non-AdCP feeds (Google Merchant Center, LinkedIn Jobs XML, hotel XML, etc.) to the standard catalog item schema without requiring the buyer to preprocess every feed. Multiple mappings can assemble a nested object via dot notation (e.g., separate mappings for price.amount and price.currency).
571
+ */
572
+ export interface CatalogFieldMapping {
573
+ /**
574
+ * Field name in the external feed record. Omit when injecting a static literal value (use the value property instead).
575
+ */
576
+ feed_field?: string;
577
+ /**
578
+ * Target field on the catalog item schema, using dot notation for nested fields (e.g., 'name', 'price.amount', 'location.city'). Mutually exclusive with asset_group_id.
579
+ */
580
+ catalog_field?: string;
581
+ /**
582
+ * Places the feed field value (a URL) into a typed asset pool on the catalog item's assets array. The value is wrapped as an image or video asset in a group with this ID. Use standard group IDs: 'images_landscape', 'images_vertical', 'images_square', 'logo', 'video'. Mutually exclusive with catalog_field.
583
+ */
584
+ asset_group_id?: string;
585
+ /**
586
+ * Static literal value to inject into catalog_field for every item, regardless of what the feed contains. Mutually exclusive with feed_field. Useful for fields the feed omits (e.g., currency when price is always USD, or a constant category value).
587
+ */
588
+ value?: unknown;
589
+ /**
590
+ * Named transform to apply to the feed field value before writing to the catalog schema. See transform-specific parameters (format, timezone, by, separator).
591
+ */
592
+ transform?: 'date' | 'divide' | 'boolean' | 'split';
593
+ /**
594
+ * For transform 'date': the input date format string (e.g., 'YYYYMMDD', 'MM/DD/YYYY', 'DD-MM-YYYY'). Output is always ISO 8601 (e.g., '2025-03-01'). Uses Unicode date pattern tokens.
595
+ */
596
+ format?: string;
597
+ /**
598
+ * For transform 'date': the timezone of the input value. IANA timezone identifier (e.g., 'UTC', 'America/New_York', 'Europe/Amsterdam'). Defaults to UTC when omitted.
599
+ */
600
+ timezone?: string;
601
+ /**
602
+ * For transform 'divide': the divisor to apply (e.g., 100 to convert integer cents to decimal dollars).
603
+ */
604
+ by?: number;
605
+ /**
606
+ * For transform 'split': the separator character or string to split on. Defaults to ','.
607
+ */
608
+ separator?: string;
609
+ /**
610
+ * Fallback value to use when feed_field is absent, null, or empty. Applied after any transform would have been applied. Allows optional feed fields to have a guaranteed baseline value.
611
+ */
612
+ default?: unknown;
613
+ ext?: ExtensionObject;
614
+ }
615
+
616
+ /**
617
+ * Catalog type. Structural types: 'offering' (AdCP Offering objects), 'product' (ecommerce entries), 'inventory' (stock per location), 'store' (physical locations), 'promotion' (deals and pricing). Vertical types: 'hotel', 'flight', 'job', 'vehicle', 'real_estate', 'education', 'destination', 'app' — each with an industry-specific item schema.
618
+ */
619
+ export type CatalogType = 'offering' | 'product' | 'inventory' | 'store' | 'promotion' | 'hotel' | 'flight' | 'job' | 'vehicle' | 'real_estate' | 'education' | 'destination' | 'app';
620
+
621
+ /**
622
+ * Identifier type that the event's content_ids field should be matched against for items in this catalog. For example, 'gtin' means content_ids values are Global Trade Item Numbers, 'sku' means retailer SKUs. Omit when using a custom identifier scheme not listed in the enum.
623
+ */
624
+ export type ContentIDType = 'sku' | 'gtin' | 'offering_id' | 'job_id' | 'hotel_id' | 'flight_id' | 'vehicle_id' | 'listing_id' | 'store_id' | 'program_id' | 'destination_id' | 'app_id';
625
+
626
+ /**
627
+ * 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.
628
+ */
629
+ export interface ContextObject {
630
+ }
631
+
632
+ /**
633
+ * Industry-standard identifier types for advertising creatives. These identifiers are managed by external registries and used across the supply chain to track and reference specific creative assets.
634
+ */
635
+ export type CreativeIdentifierType = 'ad_id' | 'isci' | 'clearcast_clock';
636
+
637
+ /**
638
+ * Creative manifest to transform or generate from. For pure generation, this should include the target format_id and any required input assets. For transformation (e.g., resizing, reformatting), this is the complete creative to adapt. When creative_id is provided, the agent resolves the creative from its library and this field is ignored.
639
+ */
640
+ export type CreativeManifest = {
641
+ format_id?: FormatReferenceStructuredObject;
642
+ format_kind?: CanonicalFormatKind;
643
+ /**
644
+ * v2 path, optional. Stable identifier matching one of the seller's product `format_options[i].capability_id` values. REQUIRED when the target product carries multiple `format_options` entries sharing the same `format_kind` (the buyer must disambiguate which option this manifest matches). When the product's `format_options` has a single entry — or multiple entries with distinct `format_kind` values — `capability_id` is OPTIONAL because `format_kind` alone routes the manifest to the right declaration.
645
+ */
646
+ capability_id?: string;
647
+ /**
648
+ * Map of slot keys to actual asset content. v1 path: each key matches an `asset_id` from the format's `assets` array (e.g., 'banner_image', 'clickthrough_url', 'video_file', 'vast_tag'). v2 path: each key matches an `asset_group_id` from the format's `slots` declaration drawn from the canonical vocabulary registry (e.g., 'images_landscape', 'video', 'landing_page_url', 'vast_tag', 'script', 'creative_brief'). Either path produces the same envelope shape; only the slot-key vocabulary differs.
649
+ *
650
+ * Each slot value is **either** a single asset object (most slots — image, video, vast_tag, landing_page_url, etc.) **or** an array of asset objects (slots with `min`/`max` counts on the format declaration — `cards` on `image_carousel`, `headlines` / `descriptions` / `images_landscape` on `responsive_creative`, etc.). Single-vs-array shape is governed by the format's `slots[].min` and `slots[].max` parameters: when `max > 1` (or when the slot is conceptually a pool), the value MUST be an array; when the slot is single-valued, the value MUST be a single object. Each asset value (single or array element) carries an `asset_type` discriminator (image, video, audio, vast, daast, text, markdown, url, html, css, webhook, javascript, brief, catalog, zip, card) that selects the matching asset schema. Validators with OpenAPI-style discriminator support use `asset_type` to report errors against only the selected branch instead of all branches.
651
+ */
652
+ assets: {
653
+ /**
654
+ * This interface was referenced by `undefined`'s JSON-Schema definition
655
+ * via the `patternProperty` "^[a-z0-9_]+$".
656
+ */
657
+ [k: string]: AssetVariant | AssetVariant[];
658
+ };
659
+ brand?: BrandReference;
660
+ /**
661
+ * Rights constraints attached to this creative. Each entry represents constraints from a single rights holder. A creative may combine multiple rights constraints (e.g., talent likeness + music license). For v1, rights constraints are informational metadata — the buyer/orchestrator manages creative lifecycle against these terms.
662
+ */
663
+ rights?: RightsConstraint[];
664
+ /**
665
+ * Industry-standard identifiers for this specific manifest (e.g., Ad-ID, ISCI, Clearcast clock number). When present, overrides creative-level identifiers. Use when different format versions of the same source creative have distinct Ad-IDs (e.g., the :15 and :30 cuts).
666
+ */
667
+ industry_identifiers?: IndustryIdentifier[];
668
+ provenance?: Provenance;
669
+ ext?: ExtensionObject;
670
+ } & (V1ManifestNamedFormatReference | V2ManifestCanonicalFormatKind);
671
+
672
+ /**
673
+ * A specific execution variant of a creative with delivery metrics. For catalog-driven packages, each catalog item rendered as a distinct ad execution is a variant — the variant's manifest includes the catalog reference with the specific item rendered. For asset group optimization, represents one combination of assets the platform selected. For generative creative, represents a platform-generated variant. For standard creatives, maps 1:1 with the creative itself.
674
+ */
675
+ export type CreativeVariant = DeliveryMetrics & {
676
+ /**
677
+ * Platform-assigned identifier for this variant
678
+ */
679
+ variant_id: string;
680
+ manifest?: CreativeManifest;
681
+ /**
682
+ * Input signals that triggered generation of this variant (Tier 3). Describes why the platform created this specific variant. Platforms should provide summarized or anonymized signals rather than raw user input. For web contexts, may include page topic or URL. For conversational contexts, an anonymized content signal. For search, query category or intent. When the content context is managed through AdCP content standards, reference the artifact directly via the artifact field.
683
+ */
684
+ generation_context?: {
685
+ /**
686
+ * Type of context that triggered generation (e.g., 'web_page', 'conversational', 'search', 'app', 'dooh')
687
+ */
688
+ context_type?: string;
689
+ /**
690
+ * Reference to the content-standards artifact that provided the generation context. Links this variant to the specific piece of content (article, video, podcast segment, etc.) where the ad was placed.
691
+ */
692
+ artifact?: {
693
+ property_id: Identifier;
694
+ /**
695
+ * Artifact identifier within the property
696
+ */
697
+ artifact_id: string;
698
+ };
699
+ ext?: ExtensionObject;
700
+ };
701
+ };
702
+
703
+ /**
704
+ * DAAST (Digital Audio Ad Serving Template) tag for third-party audio ad serving
705
+ */
706
+ export type DAASTAsset = {
707
+ /**
708
+ * Discriminator identifying this as a DAAST asset. See /schemas/creative/asset-types for the registry.
709
+ */
710
+ asset_type: 'daast';
711
+ daast_version?: DAASTVersion;
712
+ /**
713
+ * Expected audio duration in milliseconds (if known)
714
+ * @minimum 0
715
+ */
716
+ duration_ms?: number;
717
+ /**
718
+ * Tracking events supported by this DAAST tag
719
+ */
720
+ tracking_events?: DAASTTrackingEvent[];
721
+ /**
722
+ * Whether companion display ads are included
723
+ */
724
+ companion_ads?: boolean;
725
+ /**
726
+ * URL to text transcript of the audio content
727
+ */
728
+ transcript_url?: string;
729
+ provenance?: Provenance;
730
+ } & ({
731
+ /**
732
+ * Discriminator indicating DAAST is delivered via URL endpoint
733
+ */
734
+ delivery_type: 'url';
735
+ /**
736
+ * URL endpoint that returns DAAST XML
737
+ */
738
+ url: string;
739
+ } | {
740
+ /**
741
+ * Discriminator indicating DAAST is delivered as inline XML content
742
+ */
743
+ delivery_type: 'inline';
744
+ /**
745
+ * Inline DAAST XML content
746
+ */
747
+ content: string;
748
+ });
749
+
750
+ /**
751
+ * Tracking events for audio ads. Aligned to the IAB DAAST 1.1 `Tracking@event` enumeration from §3.2.1.7 of the spec (creativeView, start, firstQuartile, midpoint, thirdQuartile, complete, mute, unmute, pause, rewind, resume, skip, progress) — plus `close` (referenced descriptively in DAAST 1.1 §3.2.4.2 contrasting it with `skip`), and AdCP-flattened representations of the `Impression`, `Error`, and click elements (`<Impression>`, `<Error>`, and the click children of `<AdInteractions>`) so a single declared list can cover everything a measurement vendor wants to track. `viewable` / `notViewable` / `viewUndetermined` and `measurableImpression` / `viewableImpression` are AdCP extensions for OM-SDK Audio measurability signals (DAAST 1.1 itself does not define a `<ViewableImpression>` element). DAAST 1.1 audio-incompatible video events are deliberately omitted: no `loaded`, `playerExpand` / `playerCollapse`, `fullscreen` / `exitFullscreen`, `acceptInvitation`, `adExpand` / `adCollapse`, `minimize`, `overlayViewDuration`, or `interactiveStart`.
752
+ */
753
+ export type DAASTTrackingEvent = 'impression' | 'creativeView' | 'start' | 'firstQuartile' | 'midpoint' | 'thirdQuartile' | 'complete' | 'mute' | 'unmute' | 'pause' | 'resume' | 'rewind' | 'skip' | 'progress' | 'clickTracking' | 'customClick' | 'close' | 'error' | 'viewable' | 'notViewable' | 'viewUndetermined' | 'measurableImpression' | 'viewableImpression';
754
+
755
+ /**
756
+ * DAAST specification version
757
+ */
758
+ export type DAASTVersion = '1.0' | '1.1';
759
+
760
+ /**
761
+ * Standard delivery metrics that can be reported at media buy, package, or creative level
762
+ */
763
+ export interface DeliveryMetrics {
764
+ /**
765
+ * Impressions delivered
766
+ * @minimum 0
767
+ */
768
+ impressions?: number;
769
+ /**
770
+ * Amount spent
771
+ * @minimum 0
772
+ */
773
+ spend?: number;
774
+ /**
775
+ * Total clicks
776
+ * @minimum 0
777
+ */
778
+ clicks?: number;
779
+ /**
780
+ * Click-through rate (clicks/impressions)
781
+ * @minimum 0
782
+ * @maximum 1
783
+ */
784
+ ctr?: number;
785
+ /**
786
+ * Content engagements counted toward the billable view threshold. For video this is a platform-defined view event (e.g., 30 seconds or video midpoint); for audio/podcast it is a stream start; for other formats it follows the pricing model's view definition. When the package uses CPV pricing, spend = views × rate.
787
+ * @minimum 0
788
+ */
789
+ views?: number;
790
+ /**
791
+ * Video/audio completions. When the package has a completed_views optimization goal with view_duration_seconds, completions are counted at that threshold rather than 100% completion.
792
+ * @minimum 0
793
+ */
794
+ completed_views?: number;
795
+ /**
796
+ * Completion rate (completed_views/impressions)
797
+ * @minimum 0
798
+ * @maximum 1
799
+ */
800
+ completion_rate?: number;
801
+ /**
802
+ * Total conversions attributed to this delivery. When by_event_type is present, this equals the sum of all by_event_type[].count entries.
803
+ * @minimum 0
804
+ */
805
+ conversions?: number;
806
+ /**
807
+ * Total monetary value of attributed conversions (in the reporting currency)
808
+ * @minimum 0
809
+ */
810
+ conversion_value?: number;
811
+ /**
812
+ * Return on ad spend (conversion_value / spend)
813
+ * @minimum 0
814
+ */
815
+ roas?: number;
816
+ /**
817
+ * Cost per conversion (spend / conversions)
818
+ * @minimum 0
819
+ */
820
+ cost_per_acquisition?: number;
821
+ /**
822
+ * Fraction of `conversions` (transactions) from first-time brand buyers, 0 = none, 1 = all. For retail-media unit-volume tracking of first-time buyers, see `new_to_brand_units` (count, not rate).
823
+ * @minimum 0
824
+ * @maximum 1
825
+ */
826
+ new_to_brand_rate?: number;
827
+ /**
828
+ * Leads generated (convenience alias for by_event_type where event_type='lead')
829
+ * @minimum 0
830
+ */
831
+ leads?: number;
832
+ /**
833
+ * Incremental sales lift attributed to the campaign — sales above the control/holdout baseline. Reported as a fraction (0.15 = 15% lift) or as an absolute value depending on seller convention. The seller's `attribution_methodology` qualifier (typically `deterministic_purchase` or `modeled`) and `attribution_window` qualifier on the matching `committed_metrics` entry disambiguate the methodology and window.
834
+ * @minimum 0
835
+ */
836
+ incremental_sales_lift?: number;
837
+ /**
838
+ * Brand lift — measured change in a brand metric (awareness, consideration, favorability, purchase intent, or ad recall) attributed to the campaign. Typically panel-based or survey-based. Reported as a fraction (0.05 = 5% lift). **Multidimensional in production** — Kantar, Upwave, Cint, DV all report each dimension separately with its own sample size and confidence interval. The dimension flows through `qualifier.lift_dimension` on `committed_metrics` / `metric_aggregates` (`awareness` | `consideration` | `favorability` | `purchase_intent` | `ad_recall`); rows under different dimensions are different surveyed outcomes and must not be combined. Use `attribution_methodology: 'panel_based'` qualifier when the underlying methodology is a panel.
839
+ * @minimum 0
840
+ */
841
+ brand_lift?: number;
842
+ /**
843
+ * Store visits attributed to ad exposure. Count of incremental visits over baseline. Typically uses location-data panel methodology (`attribution_methodology: 'panel_based'`) or deterministic loyalty-card match (`attribution_methodology: 'deterministic_purchase'`).
844
+ * @minimum 0
845
+ */
846
+ foot_traffic?: number;
847
+ /**
848
+ * Incremental conversions attributed to the campaign — conversions above the control/holdout baseline. Reported as a fraction (0.10 = 10% lift) or as an absolute count depending on seller convention. Distinct from `conversions` (raw count of attributed conversions); conversion_lift requires a control group and an incrementality methodology.
849
+ * @minimum 0
850
+ */
851
+ conversion_lift?: number;
852
+ /**
853
+ * Lift in brand search query volume attributed to the campaign — measured via search-data partnerships (Google, Microsoft) or survey methodology. Reported as a fraction (0.20 = 20% lift in branded search).
854
+ * @minimum 0
855
+ */
856
+ brand_search_lift?: number;
857
+ /**
858
+ * Number of times the ad creative was displayed on a DOOH screen or played in a loop. Raw play count before any impression multiplier is applied. Mirrors `forecastable-metric.json`'s `plays` token for forecast↔delivery reconciliation. Distinct from `dooh_metrics.loop_plays` (per-screen rotation count) and from `impressions` (multiplied audience figure). Used for DOOH and broadcast inventory where buyers reconcile against forecast `plays`.
859
+ * @minimum 0
860
+ */
861
+ plays?: number;
862
+ /**
863
+ * Conversion metrics broken down by event type. Spend-derived metrics (ROAS, CPA) are only available at the package/totals level since spend cannot be attributed to individual event types.
864
+ */
865
+ by_event_type?: {
866
+ event_type: EventType;
867
+ /**
868
+ * Event source that produced these conversions (for disambiguation when multiple event sources are configured)
869
+ */
870
+ event_source_id?: string;
871
+ /**
872
+ * Number of events of this type
873
+ * @minimum 0
874
+ */
875
+ count: number;
876
+ /**
877
+ * Total monetary value of events of this type
878
+ * @minimum 0
879
+ */
880
+ value?: number;
881
+ }[];
882
+ /**
883
+ * Gross Rating Points delivered (for CPP)
884
+ * @minimum 0
885
+ */
886
+ grps?: number;
887
+ /**
888
+ * Unique reach in the units specified by reach_unit. When reach_unit is omitted, units are unspecified — do not compare reach values across packages or media buys without a common reach_unit. The measurement window for this value is declared in `reach_window`; when `reach_window` is omitted, the window is unspecified and buyers MUST NOT sum reach across reports (the value MAY be a daily snapshot, a cumulative total, or something else).
889
+ * @minimum 0
890
+ */
891
+ reach?: number;
892
+ /**
893
+ * Unit of measurement for the reach field. Aligns with the reach_unit declared on optimization goals and delivery forecasts. Required when reach is present to enable cross-platform comparison.
894
+ */
895
+ reach_unit?: ReachUnit;
896
+ /**
897
+ * Measurement window for the reported `reach` and `frequency` values in this row. Declares whether the values are a per-period snapshot, a trailing rolling window, or cumulative-to-date — without this declaration, buyers summing `reach` across rows (e.g., daily delivery reports) can silently double-count audiences. Sellers SHOULD populate this whenever `reach` is present.
898
+ */
899
+ reach_window?: {
900
+ /**
901
+ * Window semantics. `cumulative` — uniques since campaign start; the value is the total unique count to date and MUST NOT be summed across rows (each later row supersedes the earlier value). `period` — uniques within a single non-overlapping reporting period (e.g., a daily snapshot for a specific calendar day). Adjacent `period` rows do not share audiences by construction, but the same person MAY appear across multiple periods, so MUST NOT be summed across rows to compute campaign reach. `rolling` — uniques within a trailing window ending at the row's reporting timestamp (e.g., trailing-7-day reach). Adjacent rolling rows overlap and MUST NOT be summed; each row's value stands alone.
902
+ */
903
+ kind: 'cumulative' | 'period' | 'rolling';
904
+ /**
905
+ * Duration of the measurement window. REQUIRED when `kind` is `period` or `rolling` — declares the snapshot length (e.g., `{"interval": 1, "unit": "days"}` for a daily snapshot) or the trailing-window length (e.g., `{"interval": 7, "unit": "days"}` for trailing-7-day rolling reach). When `kind` is `cumulative`, this field is implicit (campaign-to-date) and SHOULD be omitted.
906
+ */
907
+ period?: Duration;
908
+ };
909
+ /**
910
+ * Average frequency per reach unit, measured over the window declared in `reach_window`. When `reach_unit` is 'households', this is average exposures per household; when 'accounts', per logged-in account; etc. When `reach_window` is omitted, the window is unspecified — buyers MUST NOT compare or average frequency values across rows.
911
+ * @minimum 0
912
+ */
913
+ frequency?: number;
914
+ /**
915
+ * Audio/video quartile completion data
916
+ */
917
+ quartile_data?: {
918
+ /**
919
+ * 25% completion views
920
+ * @minimum 0
921
+ */
922
+ q1_views?: number;
923
+ /**
924
+ * 50% completion views
925
+ * @minimum 0
926
+ */
927
+ q2_views?: number;
928
+ /**
929
+ * 75% completion views
930
+ * @minimum 0
931
+ */
932
+ q3_views?: number;
933
+ /**
934
+ * 100% completion views
935
+ * @minimum 0
936
+ */
937
+ q4_views?: number;
938
+ };
939
+ /**
940
+ * DOOH-specific metrics (only included for DOOH campaigns)
941
+ */
942
+ dooh_metrics?: {
943
+ /**
944
+ * Number of times ad played in rotation
945
+ * @minimum 0
946
+ */
947
+ loop_plays?: number;
948
+ /**
949
+ * Number of unique screens displaying the ad
950
+ * @minimum 0
951
+ */
952
+ screens_used?: number;
953
+ /**
954
+ * Total display time in seconds
955
+ * @minimum 0
956
+ */
957
+ screen_time_seconds?: number;
958
+ /**
959
+ * Actual share of voice delivered (0.0 to 1.0)
960
+ * @minimum 0
961
+ * @maximum 1
962
+ */
963
+ sov_achieved?: number;
964
+ /**
965
+ * Per-row supplementary methodology notes for DOOH impression calculation (e.g., 'rotation-based; 6-second slot weighted by 70% audience overlap'). Free-form prose for context that doesn't fit the structured measurement-vendor surface. Canonical methodology declarations belong on the measurement vendor's `get_adcp_capabilities.measurement.metrics[]` block where they're discoverable once and inherited across delivery rows; this field is for row-specific context (a particular daypart's calculation, a venue-mix exception) rather than the seller's general methodology.
966
+ */
967
+ calculation_notes?: string;
968
+ /**
969
+ * Per-venue performance breakdown
970
+ */
971
+ venue_breakdown?: {
972
+ /**
973
+ * Venue identifier
974
+ */
975
+ venue_id: string;
976
+ /**
977
+ * Human-readable venue name
978
+ */
979
+ venue_name?: string;
980
+ /**
981
+ * Venue type (e.g., 'airport', 'transit', 'retail', 'billboard')
982
+ */
983
+ venue_type?: string;
984
+ /**
985
+ * Impressions delivered at this venue
986
+ * @minimum 0
987
+ */
988
+ impressions: number;
989
+ /**
990
+ * Loop plays at this venue
991
+ * @minimum 0
992
+ */
993
+ loop_plays?: number;
994
+ /**
995
+ * Number of screens used at this venue
996
+ * @minimum 0
997
+ */
998
+ screens_used?: number;
999
+ }[];
1000
+ };
1001
+ /**
1002
+ * Viewability metrics. Viewable rate should be calculated as viewable_impressions / measurable_impressions (not total impressions), since some environments cannot measure viewability. Includes `viewed_seconds` — average in-view duration — since duration is governed by the same viewability threshold (`standard`) and shares the same `measurable_impressions` denominator.
1003
+ */
1004
+ viewability?: {
1005
+ vendor?: BrandReference;
1006
+ /**
1007
+ * Impressions where viewability could be measured. Excludes environments without measurement capability (e.g., non-Intersection Observer browsers, certain app environments). Coverage denominator for `viewable_rate` AND `viewed_seconds` — both metrics are computed over the same measurable population.
1008
+ * @minimum 0
1009
+ */
1010
+ measurable_impressions?: number;
1011
+ /**
1012
+ * Impressions that met the viewability threshold defined by the measurement standard.
1013
+ * @minimum 0
1014
+ */
1015
+ viewable_impressions?: number;
1016
+ /**
1017
+ * Viewable impression rate (viewable_impressions / measurable_impressions). Range 0.0 to 1.0.
1018
+ * @minimum 0
1019
+ * @maximum 1
1020
+ */
1021
+ viewable_rate?: number;
1022
+ /**
1023
+ * Average in-view duration per measurable impression, in seconds. Reporting-side counterpart to the `viewed_seconds` optimization metric in `optimization-goal.json`. Computed over `measurable_impressions`, not total impressions — the same denominator as `viewable_rate`. The viewability `standard` governs the threshold (e.g., MRC's 50% pixels for 1s display / 2s video) that defines when an impression is in view and therefore when the clock is running. Sellers reporting against a `viewed_seconds` optimization goal MUST populate this field.
1024
+ * @minimum 0
1025
+ */
1026
+ viewed_seconds?: number;
1027
+ standard?: ViewabilityStandard;
1028
+ };
1029
+ /**
1030
+ * Total engagements — direct interactions with the ad beyond viewing. Includes social reactions/comments/shares, story/unit opens, interactive overlay taps on CTV, companion banner interactions on audio. Platform-specific; corresponds to the 'engagements' optimization metric. Maps to DBCFM KPI_INTERACTIONS (Interaktionen) in the Reporting/Performance block.
1031
+ * @minimum 0
1032
+ */
1033
+ engagements?: number;
1034
+ /**
1035
+ * New followers, page likes, artist/podcast/channel subscribes attributed to this delivery.
1036
+ * @minimum 0
1037
+ */
1038
+ follows?: number;
1039
+ /**
1040
+ * Saves, bookmarks, playlist adds, pins attributed to this delivery.
1041
+ * @minimum 0
1042
+ */
1043
+ saves?: number;
1044
+ /**
1045
+ * Visits to the brand's in-platform page (profile, artist page, channel, or storefront) attributed to this delivery. Does not include external website clicks.
1046
+ * @minimum 0
1047
+ */
1048
+ profile_visits?: number;
1049
+ /**
1050
+ * Platform-specific engagement rate (0.0 to 1.0). Typically engagements/impressions, but definition varies by platform.
1051
+ * @minimum 0
1052
+ * @maximum 1
1053
+ */
1054
+ engagement_rate?: number;
1055
+ /**
1056
+ * Cost per click (spend / clicks)
1057
+ * @minimum 0
1058
+ */
1059
+ cost_per_click?: number;
1060
+ /**
1061
+ * Cost per completed view (spend / completed_views). Primary CPCV pricing scalar for video/audio inventory; the package's `pricing_model` is `cpcv` when this field is the billing basis.
1062
+ * @minimum 0
1063
+ */
1064
+ cost_per_completed_view?: number;
1065
+ /**
1066
+ * Cost per thousand impressions, computed as (spend / impressions) × 1000. Universal pricing scalar across CTV, display, mobile/web video, native, audio, and DOOH inventory; the package's `pricing_model` is `cpm` when this field is the billing basis. Field name aligns with the canonical `cpm` token in `enums/pricing-model.json` and `pricing-options/cpm-option.json` so buyers cross-walk pricing model → reported scalar without a translation table.
1067
+ * @minimum 0
1068
+ */
1069
+ cpm?: number;
1070
+ /**
1071
+ * Audio/podcast downloads (IAB Podcast Measurement Technical Guidelines 2.x methodology). Distinct from `views` — for podcast inventory this is the count of podcast episode downloads; for streaming audio it is the count of stream starts that meet the platform's download threshold. Prefer this over `views` for audio inventory.
1072
+ * @minimum 0
1073
+ */
1074
+ downloads?: number;
1075
+ /**
1076
+ * Items sold attributed to this delivery. Retail-media scalar distinct from `conversions` — a single conversion (transaction) may carry multiple `units_sold`. Used by retail media platforms where the buyer optimizes against unit movement, not transaction count. Attribution lookback windows are platform-specific (commonly 7/14/30 days, view-through and click-through variants); sellers SHOULD declare the window via `reporting_capabilities.measurement_windows` or `measurement_terms` rather than encoding it in this scalar.
1077
+ * @minimum 0
1078
+ */
1079
+ units_sold?: number;
1080
+ /**
1081
+ * Units sold to first-time brand buyers (count, not rate). Retail-media scalar — the unit-volume parallel to the conversion-fraction `new_to_brand_rate`. Used by retail media platforms where new-customer acquisition unit volume is a primary KPI. Same attribution-window note as `units_sold` applies.
1082
+ * @minimum 0
1083
+ */
1084
+ new_to_brand_units?: number;
1085
+ /**
1086
+ * Conversion metrics broken down by action source (website, app, in_store, etc.). Useful for omnichannel sellers where conversions occur across digital and physical channels.
1087
+ */
1088
+ by_action_source?: {
1089
+ action_source: ActionSource;
1090
+ /**
1091
+ * Event source that produced these conversions (for disambiguation when multiple event sources are configured)
1092
+ */
1093
+ event_source_id?: string;
1094
+ /**
1095
+ * Number of conversions from this action source
1096
+ * @minimum 0
1097
+ */
1098
+ count: number;
1099
+ /**
1100
+ * Total monetary value of conversions from this action source
1101
+ * @minimum 0
1102
+ */
1103
+ value?: number;
1104
+ }[];
1105
+ /**
1106
+ * Reported values for vendor-defined metrics that the product's `reporting_capabilities.vendor_metrics` declared. Each entry carries the vendor (BrandRef), the metric identifier within the vendor's vocabulary, the value, optional unit, and `measurable_impressions` as the coverage denominator — vendor measurement is rarely 100% of delivered impressions, since vendors only score impressions where their SDK fires or their panel matches. When a declared vendor metric is omitted from this array, buyers infer no measurement happened (no integration). One row per `(vendor.domain, vendor.brand_id, metric_id)` per reporting period — sellers MUST de-duplicate before emission and MUST NOT emit the same vendor metric twice; buyers MAY treat duplicate rows as a seller-side conformance bug. The structured `vendor_metric_values` array is the recommended path for vendor metrics; `additionalProperties: true` on this parent object is preserved so existing free-form vendor emissions remain conformant during migration.
1107
+ */
1108
+ vendor_metric_values?: VendorMetricValue[];
1109
+ }
1110
+
1111
+ /**
1112
+ * IPTC-aligned classification of AI involvement in producing this content
1113
+ */
1114
+ export type DigitalSourceType = 'digital_capture' | 'digital_creation' | 'trained_algorithmic_media' | 'composite_with_trained_algorithmic_media' | 'algorithmic_media' | 'composite_capture' | 'composite_synthetic' | 'human_edits' | 'data_driven_media';
1115
+
1116
+ /**
1117
+ * How long the disclosure must persist during content playback or display
1118
+ */
1119
+ export type DisclosurePersistence = 'continuous' | 'initial' | 'flexible';
1120
+
1121
+ /**
1122
+ * 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.
1123
+ */
1124
+ export type DisclosurePosition = 'prominent' | 'footer' | 'audio' | 'subtitle' | 'overlay' | 'end_card' | 'pre_roll' | 'companion';
1125
+
1126
+ /**
1127
+ * A time duration expressed as an interval and unit. Used for frequency cap windows, attribution windows, reach optimization windows, time budgets, and other time-based settings. When unit is 'campaign', interval must be 1 — the window spans the full campaign flight.
1128
+ */
1129
+ export interface Duration {
1130
+ /**
1131
+ * Number of time units. Must be 1 when unit is 'campaign'.
1132
+ * @minimum 1
1133
+ */
1134
+ interval: number;
1135
+ /**
1136
+ * Time unit. 'seconds' for sub-minute precision. 'campaign' spans the full campaign flight.
1137
+ */
1138
+ unit: 'seconds' | 'minutes' | 'hours' | 'days' | 'campaign';
1139
+ }
1140
+
1141
+ /**
1142
+ * How provenance data is carried within the content
1143
+ */
1144
+ export type EmbeddedProvenanceMethod = 'manifest_wrapper' | 'provenance_markers';
1145
+
1146
+ /**
1147
+ * Standard marketing event types for event logging, aligned with IAB ECAPI
1148
+ */
1149
+ export type EventType = 'page_view' | 'view_content' | 'select_content' | 'select_item' | 'search' | 'share' | 'add_to_cart' | 'remove_from_cart' | 'viewed_cart' | 'add_to_wishlist' | 'initiate_checkout' | 'add_payment_info' | 'purchase' | 'refund' | 'lead' | 'qualify_lead' | 'close_convert_lead' | 'disqualify_lead' | 'complete_registration' | 'subscribe' | 'start_trial' | 'app_install' | 'app_launch' | 'contact' | 'schedule' | 'donate' | 'submit_application' | 'custom';
1150
+
1151
+ /**
1152
+ * 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.
1153
+ */
1154
+ export interface ExtensionObject {
1155
+ }
1156
+
1157
+ /**
1158
+ * Format of the external feed at url. Required when url points to a non-AdCP feed (e.g., Google Merchant Center XML, Meta Product Catalog). Omit for offering-type catalogs where the feed is native AdCP JSON.
1159
+ */
1160
+ export type FeedFormat = 'google_merchant_center' | 'facebook_catalog' | 'shopify' | 'linkedin_jobs' | 'custom';
1161
+
1162
+ /**
1163
+ * 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.
1164
+ */
1165
+ export interface FormatReferenceStructuredObject {
1166
+ /**
1167
+ * 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.
1168
+ */
1169
+ agent_url: string;
1170
+ /**
1171
+ * 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.
1172
+ * @pattern ^[a-zA-Z0-9_-]+$
1173
+ */
1174
+ id: string;
1175
+ /**
1176
+ * 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.
1177
+ * @minimum 1
1178
+ */
1179
+ width?: number;
1180
+ /**
1181
+ * 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.
1182
+ * @minimum 1
1183
+ */
1184
+ height?: number;
1185
+ /**
1186
+ * Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.
1187
+ * @minimum 1
1188
+ */
1189
+ duration_ms?: number;
1190
+ }
1191
+
1192
+ /**
1193
+ * Whether the video uses a constant or variable frame rate. Broadcast and SSAI contexts require constant frame rate for seamless splicing.
1194
+ */
1195
+ export type FrameRateType = 'constant' | 'variable';
1196
+
1197
+ /**
1198
+ * Group of Pictures structure. SSAI and broadcast require closed GOPs for clean splice points; open GOPs may produce artifacts at ad boundaries.
1199
+ */
1200
+ export type GOPType = 'closed' | 'open';
1201
+
1202
+ /**
1203
+ * Inline HTML content asset. For URL-delivered HTML5 banner bundles, use the zip asset type instead. For single-URL iframe-rendered tag references, use the url asset type with an appropriate url_type.
1204
+ */
1205
+ export interface HTMLAsset {
1206
+ /**
1207
+ * Discriminator identifying this as an HTML asset. See /schemas/creative/asset-types for the registry.
1208
+ */
1209
+ asset_type: 'html';
1210
+ /**
1211
+ * HTML content
1212
+ */
1213
+ content: string;
1214
+ /**
1215
+ * HTML version (e.g., 'HTML5')
1216
+ */
1217
+ version?: string;
1218
+ /**
1219
+ * Self-declared accessibility properties for this opaque creative
1220
+ */
1221
+ accessibility?: {
1222
+ /**
1223
+ * Text alternative describing the creative content
1224
+ */
1225
+ alt_text?: string;
1226
+ /**
1227
+ * Whether the creative can be fully operated via keyboard
1228
+ */
1229
+ keyboard_navigable?: boolean;
1230
+ /**
1231
+ * Whether the creative respects prefers-reduced-motion or provides pause/stop controls
1232
+ */
1233
+ motion_control?: boolean;
1234
+ /**
1235
+ * Whether the creative has been tested with screen readers
1236
+ */
1237
+ screen_reader_tested?: boolean;
1238
+ };
1239
+ provenance?: Provenance;
1240
+ }
1241
+
1242
+ /**
1243
+ * HTTP method
1244
+ */
1245
+ export type HTTPMethod = 'GET' | 'POST';
1246
+
1247
+ /**
1248
+ * Property where the artifact appears
1249
+ */
1250
+ export interface Identifier {
1251
+ type: PropertyIdentifierTypes;
1252
+ /**
1253
+ * The identifier value. For domain type: 'example.com' matches base domain plus www and m subdomains; 'edition.example.com' matches that specific subdomain; '*.example.com' matches ALL subdomains but NOT base domain
1254
+ */
1255
+ value: string;
1256
+ }
1257
+
1258
+ /**
1259
+ * Override logo asset.
1260
+ */
1261
+ export interface ImageAsset {
1262
+ /**
1263
+ * Discriminator identifying this as an image asset. See /schemas/creative/asset-types for the registry.
1264
+ */
1265
+ asset_type: 'image';
1266
+ /**
1267
+ * URL to the image asset
1268
+ */
1269
+ url: string;
1270
+ /**
1271
+ * Width in pixels
1272
+ * @minimum 1
1273
+ */
1274
+ width: number;
1275
+ /**
1276
+ * Height in pixels
1277
+ * @minimum 1
1278
+ */
1279
+ height: number;
1280
+ /**
1281
+ * Image file format (jpg, png, gif, webp, etc.)
1282
+ */
1283
+ format?: string;
1284
+ /**
1285
+ * Alternative text for accessibility
1286
+ */
1287
+ alt_text?: string;
1288
+ provenance?: Provenance;
1289
+ }
1290
+
1291
+ /**
1292
+ * An industry-standard identifier for an advertising creative (e.g., Ad-ID, ISCI, Clearcast clock number). These identifiers are managed by external registries and used across the supply chain to track and reference specific creative assets.
1293
+ */
1294
+ export interface IndustryIdentifier {
1295
+ type: CreativeIdentifierType;
1296
+ /**
1297
+ * The identifier value (e.g., 'ABCD1234000H' for Ad-ID)
1298
+ * @maxLength 64
1299
+ */
1300
+ value: string;
1301
+ }
1302
+
1303
+ /**
1304
+ * Inline JavaScript content asset. For URL-delivered third-party tag scripts, use the url asset type with url_type 'tracker_script'. For HTML5 banner bundles that include JavaScript, use the zip asset type.
1305
+ */
1306
+ export interface JavaScriptAsset {
1307
+ /**
1308
+ * Discriminator identifying this as a JavaScript asset. See /schemas/creative/asset-types for the registry.
1309
+ */
1310
+ asset_type: 'javascript';
1311
+ /**
1312
+ * JavaScript content
1313
+ */
1314
+ content: string;
1315
+ module_type?: JavaScriptModuleType;
1316
+ /**
1317
+ * Self-declared accessibility properties for this opaque creative
1318
+ */
1319
+ accessibility?: {
1320
+ /**
1321
+ * Text alternative describing the creative content
1322
+ */
1323
+ alt_text?: string;
1324
+ /**
1325
+ * Whether the creative can be fully operated via keyboard
1326
+ */
1327
+ keyboard_navigable?: boolean;
1328
+ /**
1329
+ * Whether the creative respects prefers-reduced-motion or provides pause/stop controls
1330
+ */
1331
+ motion_control?: boolean;
1332
+ /**
1333
+ * Whether the creative has been tested with screen readers
1334
+ */
1335
+ screen_reader_tested?: boolean;
1336
+ };
1337
+ provenance?: Provenance;
1338
+ }
1339
+
1340
+ /**
1341
+ * JavaScript module type
1342
+ */
1343
+ export type JavaScriptModuleType = 'esm' | 'commonjs' | 'script';
1344
+
1345
+ /**
1346
+ * Markdown-formatted text content following CommonMark specification
1347
+ */
1348
+ export interface MarkdownAsset {
1349
+ /**
1350
+ * Discriminator identifying this as a markdown asset. See /schemas/creative/asset-types for the registry.
1351
+ */
1352
+ asset_type: 'markdown';
1353
+ /**
1354
+ * Markdown content following CommonMark spec with optional GitHub Flavored Markdown extensions
1355
+ */
1356
+ content: string;
1357
+ /**
1358
+ * Language code (e.g., 'en', 'es', 'fr')
1359
+ */
1360
+ language?: string;
1361
+ markdown_flavor?: MarkdownFlavor;
1362
+ /**
1363
+ * Whether raw HTML blocks are allowed in the markdown. False recommended for security.
1364
+ */
1365
+ allow_raw_html?: boolean;
1366
+ }
1367
+
1368
+ /**
1369
+ * Markdown flavor used. CommonMark for strict compatibility, GFM for tables/task lists/strikethrough.
1370
+ */
1371
+ export type MarkdownFlavor = 'commonmark' | 'gfm';
1372
+
1373
+ /**
1374
+ * Position of the moov atom in an MP4 container. 'start' enables progressive download without buffering the entire file; required for streaming ad delivery.
1375
+ */
1376
+ export type MoovAtomPosition = 'start' | 'end';
1377
+
1378
+ /**
1379
+ * Standard cursor-based pagination parameters for list operations
1380
+ */
1381
+ export interface PaginationRequest {
1382
+ /**
1383
+ * Maximum number of items to return per page
1384
+ * @minimum 1
1385
+ * @maximum 100
1386
+ */
1387
+ max_results?: number;
1388
+ /**
1389
+ * Opaque cursor from a previous response to fetch the next page
1390
+ */
1391
+ cursor?: string;
1392
+ }
1393
+
1394
+ /**
1395
+ * 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.
1396
+ *
1397
+ * **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.
1398
+ *
1399
+ * - **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`).
1400
+ * - **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.
1401
+ * - **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.
1402
+ * - **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.
1403
+ * - **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).
1404
+ * - **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).
1405
+ * - **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.
1406
+ * - **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.
1407
+ * - **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.
1408
+ * - **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.
1409
+ * - **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.
1410
+ */
1411
+ export interface PlatformExtensionReference {
1412
+ /**
1413
+ * 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.
1414
+ * @pattern ^https:\/\/
1415
+ */
1416
+ uri: string;
1417
+ /**
1418
+ * 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.
1419
+ * @pattern ^sha256:[a-f0-9]{64}$
1420
+ */
1421
+ digest: string;
1422
+ }
1423
+
1424
+ /**
1425
+ * Type of identifier
1426
+ */
1427
+ export type PropertyIdentifierTypes = 'domain' | 'subdomain' | 'network_id' | 'ios_bundle' | 'android_package' | 'apple_app_store_id' | 'google_play_id' | 'roku_store_id' | 'fire_tv_asin' | 'samsung_app_id' | 'apple_tv_bundle' | 'bundle_id' | 'venue_id' | 'screen_id' | 'openooh_venue_type' | 'rss_url' | 'apple_podcast_id' | 'spotify_collection_id' | 'podcast_guid' | 'station_id' | 'facility_id';
1428
+
1429
+ /**
1430
+ * Provenance metadata for this asset, overrides manifest-level provenance
1431
+ */
1432
+ export interface Provenance {
1433
+ digital_source_type?: DigitalSourceType;
1434
+ /**
1435
+ * AI system used to generate or modify this content. Aligns with IPTC 2025.1 AI metadata fields and C2PA claim_generator.
1436
+ */
1437
+ ai_tool?: {
1438
+ /**
1439
+ * Name of the AI tool or model (e.g., 'DALL-E 3', 'Stable Diffusion XL', 'Gemini')
1440
+ */
1441
+ name: string;
1442
+ /**
1443
+ * Version identifier for the AI tool or model (e.g., '25.1', '0125', '2.1'). For generative models, use the model version rather than the API version.
1444
+ */
1445
+ version?: string;
1446
+ /**
1447
+ * Organization that provides the AI tool (e.g., 'OpenAI', 'Stability AI', 'Google')
1448
+ */
1449
+ provider?: string;
1450
+ };
1451
+ /**
1452
+ * Level of human involvement in the AI-assisted creation process. Independent of `disclosure.required` — the protocol does not derive disclosure obligations from oversight level. Some regulations include carve-outs for human-edited or human-directed AI output, but those carve-outs have factual prerequisites the schema cannot evaluate. Asserting `edited` or `directed` does not by itself justify `disclosure.required: false`.
1453
+ */
1454
+ human_oversight?: 'none' | 'prompt_only' | 'selected' | 'edited' | 'directed';
1455
+ /**
1456
+ * Party declaring this provenance. Identifies who attached the provenance claim, enabling receiving parties to assess trust.
1457
+ */
1458
+ declared_by?: {
1459
+ /**
1460
+ * URL of the agent or service that declared this provenance
1461
+ */
1462
+ agent_url?: string;
1463
+ /**
1464
+ * Role of the declaring party in the supply chain
1465
+ */
1466
+ role: 'creator' | 'advertiser' | 'agency' | 'platform' | 'tool';
1467
+ };
1468
+ /**
1469
+ * When this provenance claim was made (ISO 8601). Distinct from created_time, which records when the content itself was produced. A provenance claim may be attached well after content creation, for example when retroactively declaring AI involvement for regulatory compliance.
1470
+ * @format date-time
1471
+ */
1472
+ declared_at?: string;
1473
+ /**
1474
+ * When this content was created or generated (ISO 8601)
1475
+ * @format date-time
1476
+ */
1477
+ created_time?: string;
1478
+ /**
1479
+ * C2PA sidecar manifest reference. Links to a detached cryptographic provenance manifest for this content. Note: file-level C2PA bindings break when ad servers transcode, resize, or re-encode assets. For pipelines with intermediaries, consider embedded_provenance as the primary provenance mechanism.
1480
+ */
1481
+ c2pa?: {
1482
+ /**
1483
+ * URL to the C2PA manifest store for this content
1484
+ */
1485
+ manifest_url: string;
1486
+ };
1487
+ /**
1488
+ * Provenance metadata embedded within the content stream. Each entry declares one embedding layer: structured provenance data carried inside the content itself, as distinct from sidecar references (c2pa.manifest_url). Embedded provenance survives operations that break sidecar and file-level bindings: ad-server transcoding, CMS ingestion, copy-paste, reformatting, and CDN re-encoding. For ad-tech pipelines where content passes through multiple intermediaries, embedded provenance is the reliable path for provenance that persists from declaration through delivery. This is a declaration by the embedding party. The receiving party (the seller) is the verifier-of-record: it confirms the claim by calling a governance agent it trusts (typically one published in `creative_policy.accepted_verifiers`).
1489
+ */
1490
+ embedded_provenance?: {
1491
+ method: EmbeddedProvenanceMethod;
1492
+ /**
1493
+ * Standard the embedding conforms to, if any (e.g., 'c2pa' for C2PA Section A.7 text manifest embedding)
1494
+ */
1495
+ standard?: string;
1496
+ /**
1497
+ * Organization that performed the embedding (e.g., 'Encypher', 'Digimarc'). Display label and audit context — not a wire identifier.
1498
+ */
1499
+ provider: string;
1500
+ /**
1501
+ * Buyer's representation that this embedding can be verified by a governance agent on the seller's `creative_policy.accepted_verifiers` list. The `agent_url` MUST match (canonicalized) one of the seller's published `accepted_verifiers[].agent_url` entries; sellers reject `sync_creatives` submissions whose `verify_agent.agent_url` is off-list with `PROVENANCE_VERIFIER_NOT_ACCEPTED`. This is buyer-supplied evidence, not buyer-driven routing — the seller is the verifier-of-record and the seller controls which agent it actually calls (the seller MAY use a different on-list agent if it determines this is more appropriate; the seller does not call buyer-asserted endpoints outside its allowlist). MAY be omitted for self-verifiable embeddings (e.g., a C2PA text manifest with a public key the seller already trusts).
1502
+ */
1503
+ verify_agent?: {
1504
+ /**
1505
+ * URL of the governance agent the buyer represents was used to embed/verify this layer. MUST use the `https://` scheme and MUST appear in the seller's `creative_policy.accepted_verifiers[].agent_url` list (canonicalized per /docs/reference/url-canonicalization: lowercase scheme and host, strip default port, normalize path dot-segments). Sellers MUST NOT call this URL until the canonicalized match is confirmed.
1506
+ * @pattern ^https:\/\/
1507
+ */
1508
+ agent_url: string;
1509
+ /**
1510
+ * Optional `feature_id` the buyer represents the seller should request via `get_creative_features` (e.g., `encypher.markers_present_v2`). SHOULD match the `feature_id` declared on the matching `accepted_verifiers[]` entry, or be omitted to defer the selector to the seller. When the seller's entry pins a `feature_id`, that value wins; when neither side pins, the seller selects from the agent's `governance.creative_features` catalog.
1511
+ */
1512
+ feature_id?: string;
1513
+ };
1514
+ /**
1515
+ * When the provenance data was embedded (ISO 8601)
1516
+ * @format date-time
1517
+ */
1518
+ embedded_at?: string;
1519
+ }[];
1520
+ /**
1521
+ * Content watermarks applied to this asset. Each entry declares one watermarking layer: a content modification that encodes an identifier or fingerprint within the asset. Watermarks differ from embedded provenance: a watermark encodes an identifier (who generated it, who owns it), while embedded provenance carries or references a structured provenance record (the full chain of custody). A single asset may carry both. Aligns with C2PA action taxonomy: c2pa.watermarked.bound (watermark linked to a C2PA manifest) and c2pa.watermarked.unbound (watermark independent of any manifest). This is a declaration by the watermarking party. The receiving party (the seller) is the verifier-of-record: it confirms the claim by calling a governance agent it trusts (typically one published in `creative_policy.accepted_verifiers`).
1522
+ */
1523
+ watermarks?: {
1524
+ media_type: WatermarkMediaType;
1525
+ /**
1526
+ * Organization that applied the watermark (e.g., 'Imatag', 'Steg.AI', 'Encypher'). Display label and audit context — not a wire identifier.
1527
+ */
1528
+ provider: string;
1529
+ /**
1530
+ * Buyer's representation that this watermark can be detected by a governance agent on the seller's `creative_policy.accepted_verifiers` list. The `agent_url` MUST match (canonicalized) one of the seller's published `accepted_verifiers[].agent_url` entries; sellers reject `sync_creatives` submissions whose `verify_agent.agent_url` is off-list with `PROVENANCE_VERIFIER_NOT_ACCEPTED`. This is buyer-supplied evidence, not buyer-driven routing — the seller is the verifier-of-record and the seller controls which agent it actually calls (the seller MAY use a different on-list agent if it determines this is more appropriate; the seller does not call buyer-asserted endpoints outside its allowlist).
1531
+ */
1532
+ verify_agent?: {
1533
+ /**
1534
+ * URL of the governance agent the buyer represents was used to apply/detect this watermark. MUST use the `https://` scheme and MUST appear in the seller's `creative_policy.accepted_verifiers[].agent_url` list (canonicalized per /docs/reference/url-canonicalization: lowercase scheme and host, strip default port, normalize path dot-segments). Sellers MUST NOT call this URL until the canonicalized match is confirmed.
1535
+ * @pattern ^https:\/\/
1536
+ */
1537
+ agent_url: string;
1538
+ /**
1539
+ * Optional `feature_id` the buyer represents the seller should request via `get_creative_features` (e.g., `imatag.watermark_detected`). SHOULD match the `feature_id` declared on the matching `accepted_verifiers[]` entry, or be omitted to defer the selector to the seller. When the seller's entry pins a `feature_id`, that value wins; when neither side pins, the seller selects from the agent's `governance.creative_features` catalog.
1540
+ */
1541
+ feature_id?: string;
1542
+ };
1543
+ c2pa_action?: C2PAWatermarkAction;
1544
+ /**
1545
+ * When the watermark was applied (ISO 8601)
1546
+ * @format date-time
1547
+ */
1548
+ embedded_at?: string;
1549
+ }[];
1550
+ /**
1551
+ * Regulatory disclosure requirements for this content. Indicates whether AI disclosure is required and under which jurisdictions.
1552
+ */
1553
+ disclosure?: {
1554
+ /**
1555
+ * The declaring party's claim that AI disclosure is required for this content under applicable regulations. This is a declared signal carried through the supply chain — useful as a routing and audit input — not a regulatory determination made by the protocol. Receiving parties remain responsible for their own jurisdictional analysis and should not treat `required: false` as compliance cover.
1556
+ */
1557
+ required: boolean;
1558
+ /**
1559
+ * Jurisdictions where disclosure obligations apply
1560
+ */
1561
+ jurisdictions?: {
1562
+ /**
1563
+ * ISO 3166-1 alpha-2 country code (e.g., 'US', 'DE', 'CN')
1564
+ */
1565
+ country: string;
1566
+ /**
1567
+ * Sub-national region code (e.g., 'CA' for California, 'BY' for Bavaria)
1568
+ */
1569
+ region?: string;
1570
+ /**
1571
+ * Regulation identifier (e.g., 'eu_ai_act_article_50', 'ca_sb_942', 'cn_deep_synthesis')
1572
+ */
1573
+ regulation: string;
1574
+ /**
1575
+ * Required disclosure label text for this jurisdiction, in the local language
1576
+ */
1577
+ label_text?: string;
1578
+ /**
1579
+ * How the disclosure should be rendered for this jurisdiction. Expresses the declaring party's intent for persistence and position based on regulatory requirements. Publishers control actual rendering but governance agents can audit whether guidance was followed.
1580
+ */
1581
+ render_guidance?: {
1582
+ persistence?: DisclosurePersistence;
1583
+ /**
1584
+ * Minimum display duration in milliseconds for initial persistence. Recommended when persistence is initial — without it, the duration is at the publisher's discretion. At serve time the publisher reads this from provenance since the brief is not available.
1585
+ * @minimum 1
1586
+ */
1587
+ min_duration_ms?: number;
1588
+ /**
1589
+ * Preferred disclosure positions in priority order. The first position a format supports should be used.
1590
+ */
1591
+ positions?: DisclosurePosition[];
1592
+ ext?: ExtensionObject;
1593
+ };
1594
+ }[];
1595
+ };
1596
+ /**
1597
+ * Third-party verification or detection results for this content. Multiple services may independently evaluate the same content. Provenance is a claim — verification results attached by the declaring party are supplementary. The enforcing party (e.g., seller/publisher) should run its own verification via get_creative_features or calibrate_content.
1598
+ */
1599
+ verification?: {
1600
+ /**
1601
+ * Name of the verification service (e.g., 'DoubleVerify', 'Hive Moderation', 'Reality Defender')
1602
+ */
1603
+ verified_by: string;
1604
+ /**
1605
+ * When the verification was performed (ISO 8601)
1606
+ * @format date-time
1607
+ */
1608
+ verified_time?: string;
1609
+ /**
1610
+ * Verification outcome
1611
+ */
1612
+ result: 'authentic' | 'ai_generated' | 'ai_modified' | 'inconclusive';
1613
+ /**
1614
+ * Confidence score of the verification result (0.0 to 1.0)
1615
+ * @minimum 0
1616
+ * @maximum 1
1617
+ */
1618
+ confidence?: number;
1619
+ /**
1620
+ * URL to the full verification report
1621
+ */
1622
+ details_url?: string;
1623
+ }[];
1624
+ ext?: ExtensionObject;
1625
+ }
1626
+
1627
+ /**
1628
+ * 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.
1629
+ */
1630
+ export interface PushNotificationConfig {
1631
+ /**
1632
+ * 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).
1633
+ */
1634
+ url: string;
1635
+ /**
1636
+ * 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`.
1637
+ * @minLength 1
1638
+ * @maxLength 255
1639
+ * @pattern ^[A-Za-z0-9_.:-]{1,255}$
1640
+ */
1641
+ operation_id?: string;
1642
+ /**
1643
+ * 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.
1644
+ * @minLength 16
1645
+ * @maxLength 4096
1646
+ */
1647
+ token?: string;
1648
+ /**
1649
+ * 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).
1650
+ */
1651
+ authentication?: {
1652
+ /**
1653
+ * 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.
1654
+ */
1655
+ schemes: AuthenticationScheme[];
1656
+ /**
1657
+ * 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.
1658
+ * @minLength 32
1659
+ */
1660
+ credentials: string;
1661
+ };
1662
+ }
1663
+
1664
+ /**
1665
+ * Unit of measurement for reach and audience_size metrics in this forecast. Required for cross-channel forecast comparison.
1666
+ */
1667
+ export type ReachUnit = 'individuals' | 'households' | 'devices' | 'accounts' | 'cookies' | 'custom';
1668
+
1669
+ /**
1670
+ * A reference asset that provides creative context. Carries visual materials (mood boards, product shots, example creatives) with semantic roles that tell creative agents how to use them.
1671
+ */
1672
+ export interface ReferenceAsset {
1673
+ /**
1674
+ * URL to the reference asset (image, video, or document)
1675
+ */
1676
+ url: string;
1677
+ /**
1678
+ * How the creative agent should use this asset. style_reference: match the visual style; product_shot: include this product; mood_board: overall look and feel; example_creative: example of a similar execution; logo: logo to use; strategy_doc: strategy or planning document for context; storyboard: sequential visual direction for video or multi-scene creative
1679
+ */
1680
+ role: 'style_reference' | 'product_shot' | 'mood_board' | 'example_creative' | 'logo' | 'strategy_doc' | 'storyboard';
1681
+ /**
1682
+ * Human-readable description of the asset and how it should inform creative generation
1683
+ */
1684
+ description?: string;
1685
+ }
1686
+
1687
+ /**
1688
+ * Type of rights (talent, music, etc.). Helps identify constraints when a creative combines multiple rights types.
1689
+ */
1690
+ export type RightType = 'talent' | 'character' | 'brand_ip' | 'music' | 'stock_media';
1691
+
1692
+ /**
1693
+ * Types of rights usage that can be licensed through the brand protocol. Aligned with DDEX UseType direction for interoperability with music and media rights systems.
1694
+ */
1695
+ export type RightUse = 'likeness' | 'voice' | 'name' | 'endorsement' | 'motion_capture' | 'signature' | 'catchphrase' | 'sync' | 'background_music' | 'editorial' | 'commercial' | 'ai_generated_image';
1696
+
1697
+ /**
1698
+ * Rights metadata attached to a creative manifest. Each entry represents constraints from a single rights holder. A creative may combine multiple rights constraints (e.g., talent likeness + music license). For v1, rights constraints are informational metadata — the buyer/orchestrator manages creative lifecycle against these terms.
1699
+ */
1700
+ export interface RightsConstraint {
1701
+ /**
1702
+ * Rights grant identifier from the acquire_rights response
1703
+ */
1704
+ rights_id: string;
1705
+ /**
1706
+ * The agent that granted these rights
1707
+ */
1708
+ rights_agent: {
1709
+ /**
1710
+ * MCP endpoint URL of the rights agent
1711
+ */
1712
+ url: string;
1713
+ /**
1714
+ * Agent identifier
1715
+ */
1716
+ id: string;
1717
+ };
1718
+ /**
1719
+ * Start of the rights validity period
1720
+ * @format date-time
1721
+ */
1722
+ valid_from?: string;
1723
+ /**
1724
+ * End of the rights validity period. Creative should not be served after this time.
1725
+ * @format date-time
1726
+ */
1727
+ valid_until?: string;
1728
+ /**
1729
+ * Rights uses covered by this constraint
1730
+ */
1731
+ uses: RightUse[];
1732
+ /**
1733
+ * Countries where this creative may be served under these rights (ISO 3166-1 alpha-2). If omitted, no country restriction. When both countries and excluded_countries are present, the effective set is countries minus excluded_countries.
1734
+ */
1735
+ countries?: string[];
1736
+ /**
1737
+ * Countries excluded from rights availability (ISO 3166-1 alpha-2). Use when the grant is worldwide except specific markets.
1738
+ */
1739
+ excluded_countries?: string[];
1740
+ /**
1741
+ * Maximum total impressions allowed for the full validity period (valid_from to valid_until). This is the absolute cap across all creatives using this rights grant, not a per-creative or per-period limit.
1742
+ * @minimum 1
1743
+ */
1744
+ impression_cap?: number;
1745
+ right_type?: RightType;
1746
+ /**
1747
+ * Approval status from the rights holder at manifest creation time (snapshot, not a live value)
1748
+ */
1749
+ approval_status?: 'pending' | 'approved' | 'rejected';
1750
+ /**
1751
+ * URL where downstream supply chain participants can verify this rights grant is active. Returns HTTP 200 with the current grant status, or 404 if revoked. Enables SSPs and verification vendors to confirm rights before serving.
1752
+ */
1753
+ verification_url?: string;
1754
+ ext?: ExtensionObject;
1755
+ }
1756
+
1757
+ /**
1758
+ * Video scan method. Modern digital delivery requires progressive scan; interlaced is retained for broadcast legacy content.
1759
+ */
1760
+ export type ScanType = 'progressive' | 'interlaced';
1761
+
1762
+ /**
1763
+ * 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.
1764
+ */
1765
+ export type TaskStatus = 'submitted' | 'working' | 'input-required' | 'completed' | 'canceled' | 'failed' | 'rejected' | 'auth-required' | 'unknown';
1766
+
1767
+ /**
1768
+ * Text content asset
1769
+ */
1770
+ export interface TextAsset {
1771
+ /**
1772
+ * Discriminator identifying this as a text asset. See /schemas/creative/asset-types for the registry.
1773
+ */
1774
+ asset_type: 'text';
1775
+ /**
1776
+ * Text content
1777
+ */
1778
+ content: string;
1779
+ /**
1780
+ * Language code (e.g., 'en', 'es', 'fr')
1781
+ */
1782
+ language?: string;
1783
+ provenance?: Provenance;
1784
+ }
1785
+
1786
+ /**
1787
+ * URL reference asset. `url_type` declares the mechanism a receiver uses to invoke the URL (clickthrough vs. tracker_pixel vs. tracker_script) and is distinct from the URL's purpose, which the format declares in `url-asset-requirements.role` (clickthrough, landing_page, impression_tracker, click_tracker, viewability_tracker, third_party_tracker). Senders SHOULD include `url_type` on every URL asset. When `url_type` is absent, receivers SHOULD fall back to the format's `url-asset-requirements.role` per this mapping: clickthrough/landing_page → `clickthrough`; impression_tracker/click_tracker → `tracker_pixel`; viewability_tracker → `tracker_script` (OMID and equivalent verification SDKs require a <script> tag — firing them as a pixel produces no measurement); third_party_tracker → no safe fallback (mechanism is integration-specific — DV/IAS ship both pixel and script forms — receivers MAY reject or warn). When neither `url_type` nor a format-side `role` is available, receivers MUST NOT silently pick a mechanism; they SHOULD reject the manifest. Note: VAST/DAAST tag URLs are not URL assets — use `asset_type: "vast"` (or the dedicated tracker types pending RFC #2915), not `asset_type: "url"` with a tracker_pixel mechanism.
1788
+ */
1789
+ export interface URLAsset {
1790
+ /**
1791
+ * Discriminator identifying this as a URL asset. See /schemas/creative/asset-types for the registry.
1792
+ */
1793
+ asset_type: 'url';
1794
+ /**
1795
+ * URL reference. May be a plain URI or an RFC 6570 URI template carrying AdCP universal macros (e.g., `{SKU}`, `{MEDIA_BUY_ID}`). Buyers MUST NOT pre-encode macro braces at sync time; the ad server URL-encodes substituted values at impression time. See docs/creative/universal-macros.mdx.
1796
+ */
1797
+ url: string;
1798
+ url_type?: URLAssetType;
1799
+ /**
1800
+ * Description of what this URL points to
1801
+ */
1802
+ description?: string;
1803
+ provenance?: Provenance;
1804
+ }
1805
+
1806
+ /**
1807
+ * Mechanism a receiver uses to invoke this URL (distinct from purpose, which lives in `url-asset-requirements.role`): `clickthrough` for user click destination (landing page), `tracker_pixel` for impression/event tracking via HTTP request (fires GET, expects pixel/204 response), `tracker_script` for measurement SDKs that must load as a <script> tag (OMID verification, native event trackers using method:2). SHOULD be present on every URL asset; senders that omit it force the receiver into the role-based fallback described in this schema's top-level description.
1808
+ */
1809
+ export type URLAssetType = 'clickthrough' | 'tracker_pixel' | 'tracker_script';
1810
+
1811
+ /**
1812
+ * 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.
1813
+ */
1814
+ 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';
1815
+
1816
+ /**
1817
+ * How often the platform should re-fetch the feed from url. Only applicable when url is provided. Platforms may use this as a hint for polling schedules.
1818
+ */
1819
+ export type UpdateFrequency = 'realtime' | 'hourly' | 'daily' | 'weekly';
1820
+
1821
+ /**
1822
+ * Manifest references a named format via the structured `format_id` object. The v1 path; remains supported through 4.x.
1823
+ */
1824
+ export interface V1ManifestNamedFormatReference {
1825
+ format_id: FormatReferenceStructuredObject;
1826
+ /**
1827
+ * v2 path, optional. Stable identifier matching one of the seller's product `format_options[i].capability_id` values. REQUIRED when the target product carries multiple `format_options` entries sharing the same `format_kind` (the buyer must disambiguate which option this manifest matches). When the product's `format_options` has a single entry — or multiple entries with distinct `format_kind` values — `capability_id` is OPTIONAL because `format_kind` alone routes the manifest to the right declaration.
1828
+ */
1829
+ capability_id?: string;
1830
+ /**
1831
+ * Map of slot keys to actual asset content. v1 path: each key matches an `asset_id` from the format's `assets` array (e.g., 'banner_image', 'clickthrough_url', 'video_file', 'vast_tag'). v2 path: each key matches an `asset_group_id` from the format's `slots` declaration drawn from the canonical vocabulary registry (e.g., 'images_landscape', 'video', 'landing_page_url', 'vast_tag', 'script', 'creative_brief'). Either path produces the same envelope shape; only the slot-key vocabulary differs.
1832
+ *
1833
+ * Each slot value is **either** a single asset object (most slots — image, video, vast_tag, landing_page_url, etc.) **or** an array of asset objects (slots with `min`/`max` counts on the format declaration — `cards` on `image_carousel`, `headlines` / `descriptions` / `images_landscape` on `responsive_creative`, etc.). Single-vs-array shape is governed by the format's `slots[].min` and `slots[].max` parameters: when `max > 1` (or when the slot is conceptually a pool), the value MUST be an array; when the slot is single-valued, the value MUST be a single object. Each asset value (single or array element) carries an `asset_type` discriminator (image, video, audio, vast, daast, text, markdown, url, html, css, webhook, javascript, brief, catalog, zip, card) that selects the matching asset schema. Validators with OpenAPI-style discriminator support use `asset_type` to report errors against only the selected branch instead of all branches.
1834
+ */
1835
+ assets: {
1836
+ /**
1837
+ * This interface was referenced by `undefined`'s JSON-Schema definition
1838
+ * via the `patternProperty` "^[a-z0-9_]+$".
1839
+ */
1840
+ [k: string]: AssetVariant | AssetVariant[];
1841
+ };
1842
+ brand?: BrandReference;
1843
+ /**
1844
+ * Rights constraints attached to this creative. Each entry represents constraints from a single rights holder. A creative may combine multiple rights constraints (e.g., talent likeness + music license). For v1, rights constraints are informational metadata — the buyer/orchestrator manages creative lifecycle against these terms.
1845
+ */
1846
+ rights?: RightsConstraint[];
1847
+ /**
1848
+ * Industry-standard identifiers for this specific manifest (e.g., Ad-ID, ISCI, Clearcast clock number). When present, overrides creative-level identifiers. Use when different format versions of the same source creative have distinct Ad-IDs (e.g., the :15 and :30 cuts).
1849
+ */
1850
+ industry_identifiers?: IndustryIdentifier[];
1851
+ provenance?: Provenance;
1852
+ ext?: ExtensionObject;
1853
+ }
1854
+
1855
+ /**
1856
+ * Manifest declares which canonical format it targets via `format_kind` (e.g., `image`). The v2 path introduced by RFC #3305.
1857
+ */
1858
+ export interface V2ManifestCanonicalFormatKind {
1859
+ format_kind: CanonicalFormatKind;
1860
+ /**
1861
+ * v2 path, optional. Stable identifier matching one of the seller's product `format_options[i].capability_id` values. REQUIRED when the target product carries multiple `format_options` entries sharing the same `format_kind` (the buyer must disambiguate which option this manifest matches). When the product's `format_options` has a single entry — or multiple entries with distinct `format_kind` values — `capability_id` is OPTIONAL because `format_kind` alone routes the manifest to the right declaration.
1862
+ */
1863
+ capability_id?: string;
1864
+ /**
1865
+ * Map of slot keys to actual asset content. v1 path: each key matches an `asset_id` from the format's `assets` array (e.g., 'banner_image', 'clickthrough_url', 'video_file', 'vast_tag'). v2 path: each key matches an `asset_group_id` from the format's `slots` declaration drawn from the canonical vocabulary registry (e.g., 'images_landscape', 'video', 'landing_page_url', 'vast_tag', 'script', 'creative_brief'). Either path produces the same envelope shape; only the slot-key vocabulary differs.
1866
+ *
1867
+ * Each slot value is **either** a single asset object (most slots — image, video, vast_tag, landing_page_url, etc.) **or** an array of asset objects (slots with `min`/`max` counts on the format declaration — `cards` on `image_carousel`, `headlines` / `descriptions` / `images_landscape` on `responsive_creative`, etc.). Single-vs-array shape is governed by the format's `slots[].min` and `slots[].max` parameters: when `max > 1` (or when the slot is conceptually a pool), the value MUST be an array; when the slot is single-valued, the value MUST be a single object. Each asset value (single or array element) carries an `asset_type` discriminator (image, video, audio, vast, daast, text, markdown, url, html, css, webhook, javascript, brief, catalog, zip, card) that selects the matching asset schema. Validators with OpenAPI-style discriminator support use `asset_type` to report errors against only the selected branch instead of all branches.
1868
+ */
1869
+ assets: {
1870
+ /**
1871
+ * This interface was referenced by `undefined`'s JSON-Schema definition
1872
+ * via the `patternProperty` "^[a-z0-9_]+$".
1873
+ */
1874
+ [k: string]: AssetVariant | AssetVariant[];
1875
+ };
1876
+ brand?: BrandReference;
1877
+ /**
1878
+ * Rights constraints attached to this creative. Each entry represents constraints from a single rights holder. A creative may combine multiple rights constraints (e.g., talent likeness + music license). For v1, rights constraints are informational metadata — the buyer/orchestrator manages creative lifecycle against these terms.
1879
+ */
1880
+ rights?: RightsConstraint[];
1881
+ /**
1882
+ * Industry-standard identifiers for this specific manifest (e.g., Ad-ID, ISCI, Clearcast clock number). When present, overrides creative-level identifiers. Use when different format versions of the same source creative have distinct Ad-IDs (e.g., the :15 and :30 cuts).
1883
+ */
1884
+ industry_identifiers?: IndustryIdentifier[];
1885
+ provenance?: Provenance;
1886
+ ext?: ExtensionObject;
1887
+ }
1888
+
1889
+ /**
1890
+ * VAST (Video Ad Serving Template) tag for third-party video ad serving
1891
+ */
1892
+ export type VASTAsset = {
1893
+ /**
1894
+ * Discriminator identifying this as a VAST asset. See /schemas/creative/asset-types for the registry.
1895
+ */
1896
+ asset_type: 'vast';
1897
+ vast_version?: VASTVersion;
1898
+ /**
1899
+ * Whether VPAID (Video Player-Ad Interface Definition) is supported
1900
+ */
1901
+ vpaid_enabled?: boolean;
1902
+ /**
1903
+ * Expected video duration in milliseconds (if known)
1904
+ * @minimum 0
1905
+ */
1906
+ duration_ms?: number;
1907
+ /**
1908
+ * Tracking events supported by this VAST tag
1909
+ */
1910
+ tracking_events?: VASTTrackingEvent[];
1911
+ /**
1912
+ * URL to captions file (WebVTT, SRT, etc.)
1913
+ */
1914
+ captions_url?: string;
1915
+ /**
1916
+ * URL to audio description track for visually impaired users
1917
+ */
1918
+ audio_description_url?: string;
1919
+ provenance?: Provenance;
1920
+ } & ({
1921
+ /**
1922
+ * Discriminator indicating VAST is delivered via URL endpoint
1923
+ */
1924
+ delivery_type: 'url';
1925
+ /**
1926
+ * URL endpoint that returns VAST XML
1927
+ */
1928
+ url: string;
1929
+ } | {
1930
+ /**
1931
+ * Discriminator indicating VAST is delivered as inline XML content
1932
+ */
1933
+ delivery_type: 'inline';
1934
+ /**
1935
+ * Inline VAST XML content
1936
+ */
1937
+ content: string;
1938
+ });
1939
+
1940
+ /**
1941
+ * Tracking events for video ads. Includes the IAB VAST 4.2 `Tracking@event` enumeration (vast_4.2.xsd `TrackingEvents_type`, lines 112–136), plus AdCP-flattened representations of the `Impression`, `Error`, `VideoClicks`, and `ViewableImpression` elements (which live in dedicated VAST elements, not under `<TrackingEvents>` — they are surfaced here so a single declared list can cover everything a measurement vendor wants to track). `fullscreen` / `exitFullscreen` are retained for VAST 2.x / 3.x compatibility (VAST 4.0+ replaced them with `playerExpand` / `playerCollapse`). `measurableImpression` is an AdCP extension for MRC measurability signals.
1942
+ */
1943
+ export type VASTTrackingEvent = 'impression' | 'creativeView' | 'loaded' | 'start' | 'firstQuartile' | 'midpoint' | 'thirdQuartile' | 'complete' | 'mute' | 'unmute' | 'pause' | 'resume' | 'rewind' | 'skip' | 'playerExpand' | 'playerCollapse' | 'fullscreen' | 'exitFullscreen' | 'progress' | 'acceptInvitation' | 'adExpand' | 'adCollapse' | 'minimize' | 'overlayViewDuration' | 'otherAdInteraction' | 'interactiveStart' | 'clickTracking' | 'customClick' | 'close' | 'closeLinear' | 'error' | 'viewable' | 'notViewable' | 'viewUndetermined' | 'measurableImpression' | 'viewableImpression';
1944
+
1945
+ /**
1946
+ * VAST specification version
1947
+ */
1948
+ export type VASTVersion = '2.0' | '3.0' | '4.0' | '4.1' | '4.2';
1949
+
1950
+ /**
1951
+ * Identifier for the metric within the vendor's vocabulary (e.g., `attention_units`, `gco2e_per_impression`, `demographic_reach`).
1952
+ */
1953
+ export type VendorMetricID = string;
1954
+
1955
+ /**
1956
+ * A reported value for a vendor-defined metric, emitted in `delivery-metrics.json` `vendor_metric_values` parallel to standard scalars. Identifies the vendor (BrandRef), the metric name within that vendor's vocabulary, the value, and the coverage denominator (`measurable_impressions`) — vendor measurement is rarely 100% coverage. The `breakdown` slot accommodates vendors that emit structured payloads beyond a single scalar (panel demographic breakouts, co-view ratios, incremental decompositions). To add fields beyond what this schema defines, vendors place them inside `breakdown` rather than alongside the standard envelope.
1957
+ */
1958
+ export interface VendorMetricValue {
1959
+ vendor: BrandReference;
1960
+ metric_id: VendorMetricID;
1961
+ /**
1962
+ * The reported value. Unit semantics are vendor-defined — see `unit` field below and the vendor's `brand.json` measurement-agent documentation.
1963
+ */
1964
+ value: number;
1965
+ /**
1966
+ * Unit of the value. Free-form to accommodate the heterogeneity of vendor metrics (e.g., `score`, `seconds`, `persons`, `gCO2e`, `USD`, `lift_percent`). When the value is monetary, use the ISO 4217 code (e.g., `USD`, `EUR`); for non-monetary, use whatever the vendor publishes. Optional on every row — the canonical unit lives at the vendor's measurement-agent metric definition (`brand.json` `agents[type='measurement']`). When sellers populate it inline they SHOULD match the vendor's published unit; buyers MAY resolve from the vendor's measurement agent when this field is absent.
1967
+ */
1968
+ unit?: string;
1969
+ /**
1970
+ * Number of impressions in this reporting period that the vendor was able to measure. Coverage denominator — buyers compute coverage rate as `measurable_impressions / impressions`. When absent, coverage is unspecified — buyers MUST NOT compute a coverage rate or assume full coverage. When the vendor measured zero impressions but is integrated, set to 0 explicitly. When the entry is omitted from `vendor_metric_values` entirely, the buyer infers no measurement happened (no integration). This pattern parallels `viewability.measurable_impressions` (`delivery-metrics.json#/properties/viewability`), which has handled vendor coverage in the IAS/DV/MRC ecosystem for over a decade — same convention: absence is unknown, not full.
1971
+ * @minimum 0
1972
+ */
1973
+ measurable_impressions?: number;
1974
+ /**
1975
+ * Optional structured payload for vendor metrics that don't fit a single scalar — panel demographic breakouts, co-view audience composition, incremental reach + frequency + lift decompositions. Free-form; the keys and value semantics are defined by the vendor (see the vendor's `brand.json` measurement-agent docs). Buyers MUST treat this object as opaque without consulting the vendor's documentation. Vendors place any fields beyond the standard envelope (e.g., confidence intervals, panel sizes) inside this object rather than at the top level.
1976
+ */
1977
+ breakdown?: {};
1978
+ }
1979
+
1980
+ /**
1981
+ * Video asset with URL and technical specifications including audio track properties
1982
+ */
1983
+ export interface VideoAsset {
1984
+ /**
1985
+ * Discriminator identifying this as a video asset. See /schemas/creative/asset-types for the registry.
1986
+ */
1987
+ asset_type: 'video';
1988
+ /**
1989
+ * URL to the video asset
1990
+ */
1991
+ url: string;
1992
+ /**
1993
+ * Width in pixels
1994
+ * @minimum 1
1995
+ */
1996
+ width: number;
1997
+ /**
1998
+ * Height in pixels
1999
+ * @minimum 1
2000
+ */
2001
+ height: number;
2002
+ /**
2003
+ * Video duration in milliseconds
2004
+ * @minimum 1
2005
+ */
2006
+ duration_ms?: number;
2007
+ /**
2008
+ * File size in bytes
2009
+ * @minimum 1
2010
+ */
2011
+ file_size_bytes?: number;
2012
+ /**
2013
+ * Video container format (mp4, webm, mov, etc.)
2014
+ */
2015
+ container_format?: string;
2016
+ /**
2017
+ * Video codec used (h264, h265, vp9, av1, prores, etc.)
2018
+ */
2019
+ video_codec?: string;
2020
+ /**
2021
+ * Video stream bitrate in kilobits per second
2022
+ * @minimum 1
2023
+ */
2024
+ video_bitrate_kbps?: number;
2025
+ /**
2026
+ * Frame rate as string to preserve precision (e.g., '23.976', '29.97', '30')
2027
+ */
2028
+ frame_rate?: string;
2029
+ frame_rate_type?: FrameRateType;
2030
+ scan_type?: ScanType;
2031
+ /**
2032
+ * Color space of the video
2033
+ */
2034
+ color_space?: 'rec709' | 'rec2020' | 'rec2100' | 'srgb' | 'dci_p3';
2035
+ /**
2036
+ * HDR format if applicable, or 'sdr' for standard dynamic range
2037
+ */
2038
+ hdr_format?: 'sdr' | 'hdr10' | 'hdr10_plus' | 'hlg' | 'dolby_vision';
2039
+ /**
2040
+ * Chroma subsampling format
2041
+ */
2042
+ chroma_subsampling?: '4:2:0' | '4:2:2' | '4:4:4';
2043
+ /**
2044
+ * Video bit depth
2045
+ */
2046
+ video_bit_depth?: 8 | 10 | 12;
2047
+ /**
2048
+ * GOP/keyframe interval in seconds
2049
+ */
2050
+ gop_interval_seconds?: number;
2051
+ gop_type?: GOPType;
2052
+ moov_atom_position?: MoovAtomPosition;
2053
+ /**
2054
+ * Whether the video contains an audio track
2055
+ */
2056
+ has_audio?: boolean;
2057
+ /**
2058
+ * Audio codec used (aac, aac_lc, he_aac, pcm, mp3, ac3, eac3, etc.)
2059
+ */
2060
+ audio_codec?: string;
2061
+ /**
2062
+ * Audio sampling rate in Hz (e.g., 44100, 48000)
2063
+ */
2064
+ audio_sampling_rate_hz?: number;
2065
+ audio_channels?: AudioChannelLayout;
2066
+ /**
2067
+ * Audio bit depth
2068
+ */
2069
+ audio_bit_depth?: 16 | 24 | 32;
2070
+ /**
2071
+ * Audio bitrate in kilobits per second
2072
+ * @minimum 1
2073
+ */
2074
+ audio_bitrate_kbps?: number;
2075
+ /**
2076
+ * Integrated loudness in LUFS
2077
+ */
2078
+ audio_loudness_lufs?: number;
2079
+ /**
2080
+ * True peak level in dBFS
2081
+ */
2082
+ audio_true_peak_dbfs?: number;
2083
+ /**
2084
+ * URL to captions file (WebVTT, SRT, etc.)
2085
+ */
2086
+ captions_url?: string;
2087
+ /**
2088
+ * URL to text transcript of the video content
2089
+ */
2090
+ transcript_url?: string;
2091
+ /**
2092
+ * URL to audio description track for visually impaired users
2093
+ */
2094
+ audio_description_url?: string;
2095
+ provenance?: Provenance;
2096
+ }
2097
+
2098
+ /**
2099
+ * Measurement standard. Required when metric is 'viewability' (MRC and GroupM define materially different thresholds). Omit for other metrics.
2100
+ */
2101
+ export type ViewabilityStandard = 'mrc' | 'groupm';
2102
+
2103
+ /**
2104
+ * Media category of the watermarked content
2105
+ */
2106
+ export type WatermarkMediaType = 'audio' | 'image' | 'video' | 'text';
2107
+
2108
+ /**
2109
+ * Webhook for server-side dynamic content rendering (DCO)
2110
+ */
2111
+ export interface WebhookAsset {
2112
+ /**
2113
+ * Discriminator identifying this as a webhook asset. See /schemas/creative/asset-types for the registry.
2114
+ */
2115
+ asset_type: 'webhook';
2116
+ /**
2117
+ * Webhook URL to call for dynamic content
2118
+ */
2119
+ url: string;
2120
+ method?: HTTPMethod;
2121
+ /**
2122
+ * Maximum time to wait for response in milliseconds
2123
+ * @minimum 10
2124
+ * @maximum 5000
2125
+ */
2126
+ timeout_ms?: number;
2127
+ /**
2128
+ * Universal macros that can be passed to webhook (e.g., DEVICE_TYPE, COUNTRY). See docs/creative/universal-macros.mdx for full list.
2129
+ */
2130
+ supported_macros?: (UniversalMacro | string)[];
2131
+ /**
2132
+ * Universal macros that must be provided for webhook to function
2133
+ */
2134
+ required_macros?: (UniversalMacro | string)[];
2135
+ response_type: WebhookResponseType;
2136
+ /**
2137
+ * Security configuration for webhook calls
2138
+ */
2139
+ security: {
2140
+ method: WebhookSecurityMethod;
2141
+ /**
2142
+ * Header name for HMAC signature (e.g., 'X-Signature')
2143
+ */
2144
+ hmac_header?: string;
2145
+ /**
2146
+ * Header name for API key (e.g., 'X-API-Key')
2147
+ */
2148
+ api_key_header?: string;
2149
+ };
2150
+ provenance?: Provenance;
2151
+ }
2152
+
2153
+ /**
2154
+ * Expected content type of webhook response
2155
+ */
2156
+ export type WebhookResponseType = 'html' | 'json' | 'xml' | 'javascript';
2157
+
2158
+ /**
2159
+ * Authentication method
2160
+ */
2161
+ export type WebhookSecurityMethod = 'hmac_sha256' | 'api_key' | 'none';
2162
+
2163
+ /**
2164
+ * Bundled creative asset delivered as a zip archive — typically an HTML5 banner with index.html plus supporting CSS, JS, images, and fonts. Receivers unpack the zip, validate internal structure, and serve contents from CDN. Distinct from inline HTML (html asset) and from third-party tag URLs (url asset with url_type tracker_script).
2165
+ */
2166
+ export interface ZipAsset {
2167
+ /**
2168
+ * Discriminator identifying this as a zip-bundled asset. See /schemas/creative/asset-types for the registry.
2169
+ */
2170
+ asset_type: 'zip';
2171
+ /**
2172
+ * URL where the zip archive is hosted. Must be HTTPS.
2173
+ */
2174
+ url: string;
2175
+ /**
2176
+ * Maximum file size in kilobytes. Receivers should reject zips exceeding this.
2177
+ * @minimum 0
2178
+ */
2179
+ max_file_size_kb?: number;
2180
+ /**
2181
+ * Relative path to the entry file within the zip (typically 'index.html'). Receivers default to 'index.html' if absent.
2182
+ */
2183
+ entry_point?: string;
2184
+ /**
2185
+ * File extensions permitted inside the zip (e.g., ['html', 'css', 'js', 'png', 'jpg', 'svg', 'webp', 'json', 'woff2']). Receivers may reject zips containing other extensions.
2186
+ */
2187
+ allowed_inner_extensions?: string[];
2188
+ /**
2189
+ * Fallback image URL for environments that cannot render the bundled creative (e.g., non-HTML5 endpoints, ad blockers). Recommended for HTML5 banners.
2190
+ */
2191
+ backup_image_url?: string;
2192
+ /**
2193
+ * Optional SHA-256 content digest of the zip archive (sha256:<hex>) for integrity verification. Lets receivers detect tampered or stale archives.
2194
+ * @pattern ^sha256:[a-f0-9]{64}$
2195
+ */
2196
+ digest?: string;
2197
+ /**
2198
+ * Self-declared accessibility properties for this opaque creative
2199
+ */
2200
+ accessibility?: {
2201
+ /**
2202
+ * Text alternative describing the creative content
2203
+ */
2204
+ alt_text?: string;
2205
+ /**
2206
+ * Whether the creative can be fully operated via keyboard
2207
+ */
2208
+ keyboard_navigable?: boolean;
2209
+ /**
2210
+ * Whether the creative respects prefers-reduced-motion or provides pause/stop controls
2211
+ */
2212
+ motion_control?: boolean;
2213
+ /**
2214
+ * Whether the creative has been tested with screen readers
2215
+ */
2216
+ screen_reader_tested?: boolean;
2217
+ };
2218
+ provenance?: Provenance;
2219
+ }