@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,3047 @@
1
+ // AUTO-GENERATED — DO NOT EDIT.
2
+ // Per-tool .d.ts slice for `update_media_buy`. 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 updating campaign and package settings
13
+ */
14
+ export interface UpdateMediaBuyRequest {
15
+ /**
16
+ * Release-precision AdCP version (VERSION.RELEASE, e.g. "3.0", "3.1", "3.1-beta"). On a request: the buyer's release pin — the seller validates against its supported_versions and returns VERSION_UNSUPPORTED on cross-major mismatch, or downshifts to the highest supported release within the same major. On a response: the release the seller actually served — clients SHOULD validate the response against that release's schema, not against their pin. Patches are not negotiated; surface them as build_version on capabilities for operational visibility. When omitted, falls back to adcp_major_version (deprecated) or server default. Buyers SHOULD emit both adcp_version and adcp_major_version through 3.x to remain compatible with sellers that only read the legacy field. NORMALIZATION: SDKs that read full-semver values from bundle metadata (e.g. ComplianceIndex.published_version = "3.1.0-beta.1") MUST normalize to release-precision ("3.1-beta.1") before emitting on the wire — meta-field values are NOT valid wire values.
17
+ */
18
+ adcp_version?: string;
19
+ /**
20
+ * DEPRECATED in favor of adcp_version (release-precision string). Servers MUST continue to honor this field through 3.x. Removed in 4.0. Original semantics: the AdCP major version the buyer's payloads conform to. Sellers validate against their supported major_versions and return VERSION_UNSUPPORTED if unsupported. When omitted, the seller assumes its highest supported version.
21
+ */
22
+ adcp_major_version?: number;
23
+ account: AccountReference;
24
+ /**
25
+ * Seller's ID of the media buy to update
26
+ */
27
+ media_buy_id: string;
28
+ /**
29
+ * Expected current revision for optimistic concurrency. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match. Obtain from get_media_buys or the most recent update response.
30
+ * @minimum 1
31
+ */
32
+ revision?: number;
33
+ /**
34
+ * Pause/resume the entire media buy (true = paused, false = active)
35
+ */
36
+ paused?: boolean;
37
+ /**
38
+ * Cancel the entire media buy. Cancellation is irreversible — canceled media buys cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE if the media buy cannot be canceled in its current state.
39
+ */
40
+ canceled?: true;
41
+ /**
42
+ * Reason for cancellation. Sellers SHOULD store this and return it in subsequent get_media_buys responses.
43
+ * @maxLength 500
44
+ */
45
+ cancellation_reason?: string;
46
+ start_time?: StartTiming;
47
+ /**
48
+ * New end date/time in ISO 8601 format
49
+ * @format date-time
50
+ */
51
+ end_time?: string;
52
+ /**
53
+ * Package-specific updates for existing packages
54
+ */
55
+ packages?: PackageUpdate[];
56
+ invoice_recipient?: BusinessEntity;
57
+ /**
58
+ * New packages to add to this media buy. Uses the same schema as create_media_buy packages. Sellers that support mid-flight package additions advertise `add_packages` in both `valid_actions[]` (deprecated) and as an entry in `available_actions[]` (authoritative). Sellers that do not support this MUST reject with ACTION_NOT_ALLOWED (preferred) or UNSUPPORTED_FEATURE (legacy).
59
+ */
60
+ new_packages?: PackageRequest[];
61
+ reporting_webhook?: ReportingWebhook;
62
+ push_notification_config?: PushNotificationConfig;
63
+ /**
64
+ * Client-generated idempotency key for safe retries. If an update fails without a response, resending with the same idempotency_key guarantees the update is applied at most once. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.
65
+ * @minLength 16
66
+ * @maxLength 255
67
+ * @pattern ^[A-Za-z0-9_.:-]{16,255}$
68
+ */
69
+ idempotency_key: string;
70
+ context?: ContextObject;
71
+ ext?: ExtensionObject;
72
+ }
73
+
74
+ /**
75
+ * Response payload for update_media_buy task. Exactly one of three shapes: (1) synchronous success — media_buy_id and updated state are issued in-line; (2) terminal failure — an errors array with no changes applied; (3) submitted task envelope — status 'submitted' with task_id when the update is queued for async processing (e.g., awaiting operator re-approval for mid-flight changes). The submitted branch MAY carry advisory errors for non-blocking warnings; terminal failures belong in the error branch. These three shapes are mutually exclusive — a response has exactly one.
76
+ */
77
+ export type UpdateMediaBuyResponse = {
78
+ /**
79
+ * 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).
80
+ */
81
+ context_id?: string;
82
+ context?: ContextObject;
83
+ /**
84
+ * Unique identifier for tracking asynchronous operations. Present when a task requires extended processing time. Used to query task status and retrieve results when complete.
85
+ */
86
+ task_id?: string;
87
+ status: TaskStatus;
88
+ /**
89
+ * 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.
90
+ */
91
+ message?: string;
92
+ /**
93
+ * ISO 8601 timestamp when the response was generated. Useful for debugging, logging, cache validation, and tracking async operation progress.
94
+ */
95
+ timestamp?: string;
96
+ /**
97
+ * 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.
98
+ */
99
+ replayed?: boolean;
100
+ adcp_error?: Error;
101
+ push_notification_config?: PushNotificationConfig;
102
+ /**
103
+ * 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.
104
+ *
105
+ * 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.
106
+ *
107
+ * This is the primary correlation key for audit and reporting across the governance lifecycle.
108
+ */
109
+ governance_context?: string;
110
+ /**
111
+ * 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.
112
+ */
113
+ payload?: {};
114
+ /**
115
+ * 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.
116
+ */
117
+ adcp_version?: string;
118
+ /**
119
+ * 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.
120
+ */
121
+ adcp_major_version?: number;
122
+ } & (UpdateMediaBuySuccess | UpdateMediaBuyError | UpdateMediaBuySubmitted);
123
+
124
+ /**
125
+ * Success response - media buy updated successfully
126
+ */
127
+ export interface UpdateMediaBuySuccess {
128
+ /**
129
+ * Seller's identifier for the media buy
130
+ */
131
+ media_buy_id: string;
132
+ media_buy_status?: MediaBuyStatus;
133
+ status?: MediaBuyStatus;
134
+ /**
135
+ * Revision number after this update. Use this value in subsequent update_media_buy requests for optimistic concurrency.
136
+ * @minimum 1
137
+ */
138
+ revision?: number;
139
+ /**
140
+ * ISO 4217 currency code for monetary values at this media buy level. Echoed when the update affects budget or currency. Matches the currency field in subsequent get_media_buys responses.
141
+ * @pattern ^[A-Z]{3}$
142
+ */
143
+ currency?: string;
144
+ /**
145
+ * Updated total budget amount across all packages, denominated in currency. Echoed when the update affects package budgets so buyers can verify the new aggregate without a round-trip to get_media_buys. Matches the total_budget field in subsequent get_media_buys responses.
146
+ * @minimum 0
147
+ */
148
+ total_budget?: number;
149
+ /**
150
+ * ISO 8601 timestamp when changes take effect (null if pending approval)
151
+ * @format date-time
152
+ */
153
+ implementation_date?: string | null;
154
+ invoice_recipient?: BusinessEntity;
155
+ /**
156
+ * Array of packages that were modified with complete state information
157
+ */
158
+ affected_packages?: Package[];
159
+ /**
160
+ * Flat-vocabulary actions the buyer can perform after this update. Saves a round-trip to get_media_buys. Deprecated in favor of `available_actions[]`, which carries `mode`, optional SLA, and optional `terms_ref`. Sellers SHOULD populate both during the 3.x deprecation window; consumers MUST prefer `available_actions[]` when both are present. Removed in 4.0.
161
+ */
162
+ valid_actions?: MediaBuyValidAction[];
163
+ /**
164
+ * Structured per-buy resolution of actions available after this update. Authoritative — see `get-media-buys-response.json` for full semantics.
165
+ */
166
+ available_actions?: MediaBuyAvailableAction[];
167
+ /**
168
+ * When true, this response contains simulated data from sandbox mode.
169
+ */
170
+ sandbox?: boolean;
171
+ context?: ContextObject;
172
+ ext?: ExtensionObject;
173
+ }
174
+
175
+ /**
176
+ * Error response - operation failed, no changes applied
177
+ */
178
+ export interface UpdateMediaBuyError {
179
+ /**
180
+ * Array of errors explaining why the operation failed
181
+ */
182
+ errors: Error[];
183
+ context?: ContextObject;
184
+ ext?: ExtensionObject;
185
+ }
186
+
187
+ /**
188
+ * Async task envelope returned when update_media_buy cannot be confirmed before the response — for example, when operator re-approval is required for mid-flight changes. The buyer polls tasks/get with task_id or receives a webhook when the task completes; the updated media buy state lands on the completion artifact, not this envelope.
189
+ */
190
+ export interface UpdateMediaBuySubmitted {
191
+ /**
192
+ * Task-level status literal. Discriminates this async envelope from the synchronous success shape, whose media_buy_id is issued in-line. See task-status.json for the full task-status enum.
193
+ */
194
+ status: 'submitted';
195
+ /**
196
+ * Task handle the buyer uses with tasks/get, and that the seller references on push-notification callbacks. Per AdCP wire conventions this is snake_case; A2A adapters MAY surface it as taskId, but the payload field emitted by the agent is task_id.
197
+ */
198
+ task_id: string;
199
+ /**
200
+ * Optional human-readable explanation of why the task is submitted — e.g., 'Awaiting operator re-approval; typical turnaround 2–4 hours.' Plain text only. Buyers MUST treat this as untrusted seller input: escape before rendering to HTML UIs, and sanitize or isolate before passing to an LLM prompt context — a hostile seller may inject prompt-injection payloads aimed at the buyer's agent.
201
+ * @maxLength 2000
202
+ */
203
+ message?: string;
204
+ /**
205
+ * Optional advisory errors accompanying the submitted envelope. Use only for non-blocking warnings (e.g., throttled_severity advisories, governance observations). Terminal failures belong in the error branch, not here.
206
+ */
207
+ errors?: Error[];
208
+ context?: ContextObject;
209
+ ext?: ExtensionObject;
210
+ }
211
+
212
+ /**
213
+ * Account for product lookup. Returns products with pricing specific to this account's rate card.
214
+ */
215
+ export type AccountReference = {
216
+ /**
217
+ * Seller-assigned account identifier (from sync_accounts or list_accounts)
218
+ */
219
+ account_id: string;
220
+ } | {
221
+ brand: BrandReference;
222
+ /**
223
+ * Domain of the entity operating on the brand's behalf. When the brand operates directly, this is the brand's domain.
224
+ * @pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$
225
+ */
226
+ operator: string;
227
+ /**
228
+ * When true, references the sandbox account for this brand/operator pair. Defaults to false (production account).
229
+ */
230
+ sandbox?: boolean;
231
+ };
232
+
233
+ /**
234
+ * Methods for verifying user age for compliance. Does not include 'inferred' as it is not accepted for regulatory compliance.
235
+ */
236
+ export type AgeVerificationMethod = 'facial_age_estimation' | 'id_document' | 'digital_id' | 'credit_card' | 'world_id';
237
+
238
+ /**
239
+ * 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.
240
+ */
241
+ export type AssetVariant = ImageAsset | VideoAsset | AudioAsset | VASTAsset | TextAsset | URLAsset | HTMLAsset | JavaScriptAsset | ZipAsset | WebhookAsset | CSSAsset | DAASTAsset | MarkdownAsset | BriefAsset | CatalogAsset | CardAsset;
242
+
243
+ /**
244
+ * How attribution between ad exposure and outcome events was computed. Used as a `qualifier.attribution_methodology` key on `committed_metrics`, `missing_metrics`, `metric_aggregates`, and `performance-feedback.metric` to disambiguate the same outcome metric reported under different methodologies — `conversion_value` measured deterministically (matched purchase IDs) is not the same number as `conversion_value` measured probabilistically (modeled match) and should never be summed across methodologies. The retail-media closed-loop pattern typically reports under `deterministic_purchase`; MMM and clean-room outputs typically report under `modeled` or `probabilistic`; panel-based measurement (Nielsen, comScore, Edison) reports under `panel_based`.
245
+ */
246
+ export type AttributionMethodology = 'deterministic_purchase' | 'probabilistic' | 'panel_based' | 'modeled';
247
+
248
+ /**
249
+ * Attribution model used to assign credit when multiple touchpoints exist. SHOULD be populated when committing to a specific model; when absent, the seller's default applies.
250
+ */
251
+ export type AttributionModel = 'last_touch' | 'first_touch' | 'linear' | 'time_decay' | 'data_driven';
252
+
253
+ /**
254
+ * Describes the attribution methodology and lookback windows used for conversion measurement. Enables cross-platform comparison by making attribution methodology transparent. Used as a `$ref` from `optimization-goal.json` (buyer's optimization-time attribution choice), `get-media-buy-delivery-response.json` (seller-declared attribution methodology in delivery reports), and similar surfaces. All fields are optional individually but at least one of `post_click`, `post_view`, or `model` SHOULD be populated; absence of `model` means the seller's default attribution model applies (typically `last_touch` per industry convention) — sellers SHOULD populate `model` explicitly when committing to a specific methodology.
255
+ */
256
+ export interface AttributionWindow {
257
+ /**
258
+ * Post-click attribution window. Conversions occurring within this duration after a click are attributed to the ad.
259
+ */
260
+ post_click?: Duration;
261
+ /**
262
+ * Post-view attribution window. Conversions occurring within this duration after an ad impression (without click) are attributed to the ad.
263
+ */
264
+ post_view?: Duration;
265
+ model?: AttributionModel;
266
+ }
267
+
268
+ /**
269
+ * Audio asset with URL and technical specifications
270
+ */
271
+ export interface AudioAsset {
272
+ /**
273
+ * Discriminator identifying this as an audio asset. See /schemas/creative/asset-types for the registry.
274
+ */
275
+ asset_type: 'audio';
276
+ /**
277
+ * URL to the audio asset
278
+ */
279
+ url: string;
280
+ /**
281
+ * Audio duration in milliseconds
282
+ * @minimum 0
283
+ */
284
+ duration_ms?: number;
285
+ /**
286
+ * File size in bytes
287
+ * @minimum 1
288
+ */
289
+ file_size_bytes?: number;
290
+ /**
291
+ * Audio container/file format (mp3, m4a, aac, wav, ogg, flac, etc.)
292
+ */
293
+ container_format?: string;
294
+ /**
295
+ * Audio codec used (aac, aac_lc, he_aac, pcm, mp3, vorbis, opus, flac, ac3, eac3, etc.)
296
+ */
297
+ codec?: string;
298
+ /**
299
+ * Sampling rate in Hz (e.g., 44100, 48000, 96000)
300
+ */
301
+ sampling_rate_hz?: number;
302
+ channels?: AudioChannelLayout;
303
+ /**
304
+ * Bit depth
305
+ */
306
+ bit_depth?: 16 | 24 | 32;
307
+ /**
308
+ * Bitrate in kilobits per second
309
+ * @minimum 1
310
+ */
311
+ bitrate_kbps?: number;
312
+ /**
313
+ * Integrated loudness in LUFS
314
+ */
315
+ loudness_lufs?: number;
316
+ /**
317
+ * True peak level in dBFS
318
+ */
319
+ true_peak_dbfs?: number;
320
+ /**
321
+ * URL to text transcript of the audio content
322
+ */
323
+ transcript_url?: string;
324
+ provenance?: Provenance;
325
+ }
326
+
327
+ /**
328
+ * Audio channel configuration
329
+ */
330
+ export type AudioChannelLayout = 'mono' | 'stereo' | '5.1' | '7.1';
331
+
332
+ /**
333
+ * 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.
334
+ */
335
+ export type AuthenticationScheme = 'Bearer' | 'HMAC-SHA256';
336
+
337
+ /**
338
+ * Standard delivery and performance metrics available for reporting
339
+ */
340
+ export type AvailableMetric = 'impressions' | 'spend' | 'clicks' | 'ctr' | 'views' | 'completed_views' | 'completion_rate' | 'conversions' | 'conversion_value' | 'roas' | 'cost_per_acquisition' | 'new_to_brand_rate' | 'leads' | 'reach' | 'frequency' | 'grps' | 'engagements' | 'engagement_rate' | 'follows' | 'saves' | 'profile_visits' | 'viewability' | 'quartile_data' | 'dooh_metrics' | 'cost_per_click' | 'cost_per_completed_view' | 'cpm' | 'downloads' | 'units_sold' | 'new_to_brand_units' | 'plays' | 'incremental_sales_lift' | 'brand_lift' | 'foot_traffic' | 'conversion_lift' | 'brand_search_lift';
341
+
342
+ /**
343
+ * Brand identifier within the house portfolio. Optional for single-brand domains.
344
+ */
345
+ export type BrandID = string;
346
+
347
+ /**
348
+ * Brand reference for product discovery context. Resolved to full brand identity at execution time.
349
+ */
350
+ export interface BrandReference {
351
+ /**
352
+ * Domain where /.well-known/brand.json is hosted, or the brand's operating domain
353
+ * @pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$
354
+ */
355
+ domain: string;
356
+ brand_id?: BrandID;
357
+ /**
358
+ * 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.
359
+ */
360
+ industries?: string[];
361
+ /**
362
+ * 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.
363
+ */
364
+ data_subject_contestation?: {
365
+ [k: string]: unknown | undefined;
366
+ };
367
+ /**
368
+ * 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.
369
+ *
370
+ * **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.
371
+ */
372
+ brand_kit_override?: {
373
+ logo?: ImageAsset;
374
+ /**
375
+ * Override brand colors (hex strings).
376
+ */
377
+ colors?: {
378
+ /**
379
+ * @pattern ^#[0-9a-fA-F]{6}$
380
+ */
381
+ primary?: string;
382
+ /**
383
+ * @pattern ^#[0-9a-fA-F]{6}$
384
+ */
385
+ secondary?: string;
386
+ /**
387
+ * @pattern ^#[0-9a-fA-F]{6}$
388
+ */
389
+ accent?: string;
390
+ };
391
+ /**
392
+ * Override brand-voice description for surface-composed text/audio output.
393
+ */
394
+ voice?: string;
395
+ /**
396
+ * Override tagline.
397
+ */
398
+ tagline?: string;
399
+ };
400
+ }
401
+
402
+ /**
403
+ * 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.
404
+ */
405
+ export interface BriefAsset {
406
+ /**
407
+ * Campaign or flight name for identification
408
+ */
409
+ name: string;
410
+ /**
411
+ * Campaign objective that guides creative tone and call-to-action strategy
412
+ */
413
+ objective?: 'awareness' | 'consideration' | 'conversion' | 'retention' | 'engagement';
414
+ /**
415
+ * Desired tone for this campaign, modulating the brand's base tone (e.g., 'playful and festive', 'premium and aspirational')
416
+ */
417
+ tone?: string;
418
+ /**
419
+ * Target audience description for this campaign
420
+ */
421
+ audience?: string;
422
+ /**
423
+ * Creative territory or positioning the campaign should occupy
424
+ */
425
+ territory?: string;
426
+ /**
427
+ * Messaging framework for the campaign
428
+ */
429
+ messaging?: {
430
+ /**
431
+ * Primary headline
432
+ */
433
+ headline?: string;
434
+ /**
435
+ * Supporting tagline or sub-headline
436
+ */
437
+ tagline?: string;
438
+ /**
439
+ * Call-to-action text
440
+ */
441
+ cta?: string;
442
+ /**
443
+ * Key messages to communicate in priority order
444
+ */
445
+ key_messages?: string[];
446
+ };
447
+ /**
448
+ * Visual and strategic reference materials such as mood boards, product shots, example creatives, and strategy documents
449
+ */
450
+ reference_assets?: ReferenceAsset[];
451
+ /**
452
+ * Regulatory and legal compliance requirements for this campaign. Campaign-specific, regional, and product-based — distinct from brand-level disclaimers in brand.json.
453
+ */
454
+ compliance?: {
455
+ /**
456
+ * Disclosures that must appear in creatives for this campaign. Each disclosure specifies the text, where it should appear, and which jurisdictions require it.
457
+ */
458
+ required_disclosures?: {
459
+ /**
460
+ * The disclosure text that must appear in the creative
461
+ */
462
+ text: string;
463
+ position?: DisclosurePosition;
464
+ /**
465
+ * 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.
466
+ */
467
+ jurisdictions?: string[];
468
+ /**
469
+ * The regulation or legal authority requiring this disclosure (e.g., 'SEC Rule 156', 'FCA COBS 4.5', 'FDA 21 CFR 202')
470
+ */
471
+ regulation?: string;
472
+ /**
473
+ * 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.
474
+ */
475
+ min_duration_ms?: number;
476
+ /**
477
+ * 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.
478
+ */
479
+ language?: string;
480
+ persistence?: DisclosurePersistence;
481
+ }[];
482
+ /**
483
+ * Claims that must not appear in creatives for this campaign. Creative agents should ensure generated content avoids these claims.
484
+ */
485
+ prohibited_claims?: string[];
486
+ };
487
+ /**
488
+ * Discriminator identifying this as a brief asset. See /schemas/creative/asset-types for the registry.
489
+ */
490
+ asset_type: 'brief';
491
+ }
492
+
493
+ /**
494
+ * Override the account's default billing entity for this specific buy. When provided, the seller invoices this entity instead. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request.
495
+ */
496
+ export interface BusinessEntity {
497
+ /**
498
+ * Registered legal name of the business entity
499
+ * @maxLength 200
500
+ */
501
+ legal_name: string;
502
+ /**
503
+ * VAT identification number (e.g., DE123456789 for Germany, FR12345678901 for France). Required for B2B invoicing in the EU. Must be normalized: no spaces, dots, or dashes.
504
+ * @pattern ^[A-Z]{2}[A-Z0-9]{2,13}$
505
+ */
506
+ vat_id?: string;
507
+ /**
508
+ * Tax identification number for jurisdictions that do not use VAT (e.g., US EIN)
509
+ * @maxLength 30
510
+ */
511
+ tax_id?: string;
512
+ /**
513
+ * Company registration number (e.g., HRB 12345 for German Handelsregister)
514
+ * @maxLength 50
515
+ */
516
+ registration_number?: string;
517
+ /**
518
+ * Postal address for invoicing and legal correspondence
519
+ */
520
+ address?: {
521
+ /**
522
+ * Street address including building number
523
+ * @maxLength 200
524
+ */
525
+ street: string;
526
+ /**
527
+ * @maxLength 100
528
+ */
529
+ city: string;
530
+ /**
531
+ * @maxLength 20
532
+ */
533
+ postal_code: string;
534
+ /**
535
+ * State, province, or region
536
+ * @maxLength 100
537
+ */
538
+ region?: string;
539
+ /**
540
+ * ISO 3166-1 alpha-2 country code
541
+ * @pattern ^[A-Z]{2}$
542
+ */
543
+ country: string;
544
+ };
545
+ /**
546
+ * Contacts for billing, legal, and operational matters. Contains personal data subject to GDPR and equivalent regulations. Implementations MUST use this data only for invoicing and account management.
547
+ */
548
+ contacts?: {
549
+ /**
550
+ * Contact's functional role in the business relationship
551
+ */
552
+ role: 'billing' | 'legal' | 'creative' | 'general';
553
+ /**
554
+ * Full name of the contact
555
+ * @maxLength 200
556
+ */
557
+ name?: string;
558
+ /**
559
+ * @maxLength 254
560
+ * @format email
561
+ */
562
+ email?: string;
563
+ /**
564
+ * @maxLength 30
565
+ */
566
+ phone?: string;
567
+ }[];
568
+ /**
569
+ * Bank account details for payment processing. Write-only: included in requests to provide payment coordinates, but MUST NOT be echoed in responses. Sellers store these details and confirm receipt without returning them.
570
+ */
571
+ bank?: {
572
+ /**
573
+ * Name on the bank account
574
+ * @maxLength 200
575
+ */
576
+ account_holder: string;
577
+ /**
578
+ * International Bank Account Number (SEPA markets)
579
+ * @pattern ^[A-Z]{2}[0-9]{2}[A-Z0-9]{4,30}$
580
+ */
581
+ iban?: string;
582
+ /**
583
+ * Bank Identifier Code / SWIFT code (SEPA markets)
584
+ * @pattern ^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$
585
+ */
586
+ bic?: string;
587
+ /**
588
+ * Bank routing number for non-SEPA markets (e.g., US ABA routing number, Canadian transit/institution number)
589
+ * @maxLength 30
590
+ */
591
+ routing_number?: string;
592
+ /**
593
+ * Bank account number for non-SEPA markets
594
+ * @maxLength 30
595
+ */
596
+ account_number?: string;
597
+ };
598
+ ext?: ExtensionObject;
599
+ }
600
+
601
+ /**
602
+ * C2PA action classification for this watermark
603
+ */
604
+ export type C2PAWatermarkAction = 'c2pa.watermarked.bound' | 'c2pa.watermarked.unbound';
605
+
606
+ /**
607
+ * CSS stylesheet asset
608
+ */
609
+ export interface CSSAsset {
610
+ /**
611
+ * Discriminator identifying this as a CSS asset. See /schemas/creative/asset-types for the registry.
612
+ */
613
+ asset_type: 'css';
614
+ /**
615
+ * CSS content
616
+ */
617
+ content: string;
618
+ /**
619
+ * CSS media query context (e.g., 'screen', 'print')
620
+ */
621
+ media?: string;
622
+ provenance?: Provenance;
623
+ }
624
+
625
+ /**
626
+ * Which party initiated the package cancellation.
627
+ */
628
+ export type CanceledBy = 'buyer' | 'seller';
629
+
630
+ /**
631
+ * 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`).
632
+ */
633
+ 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';
634
+
635
+ /**
636
+ * 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"`).
637
+ *
638
+ * 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`.
639
+ *
640
+ * 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.
641
+ */
642
+ export interface CardAsset {
643
+ /**
644
+ * Discriminator identifying this as a card asset. See /schemas/creative/asset-types for the registry.
645
+ */
646
+ asset_type: 'card';
647
+ /**
648
+ * The card's primary visual asset. Either an `image` or `video` asset, matching the parent format's `allowed_card_media_asset_types` parameter.
649
+ */
650
+ media: ImageAsset | VideoAsset;
651
+ /**
652
+ * 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.
653
+ */
654
+ headline?: string;
655
+ /**
656
+ * 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.
657
+ */
658
+ description?: string;
659
+ /**
660
+ * 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.
661
+ */
662
+ cta?: string;
663
+ landing_page_url?: URLAsset;
664
+ /**
665
+ * 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.
666
+ */
667
+ platform_extensions?: PlatformExtensionReference[];
668
+ provenance?: Provenance;
669
+ }
670
+
671
+ /**
672
+ * Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.
673
+ */
674
+ export interface Catalog {
675
+ /**
676
+ * Buyer's identifier for this catalog. Required when syncing via sync_catalogs. When used in creatives, references a previously synced catalog on the account.
677
+ */
678
+ catalog_id?: string;
679
+ /**
680
+ * Human-readable name for this catalog (e.g., 'Summer Products 2025', 'Amsterdam Store Locations').
681
+ */
682
+ name?: string;
683
+ type: CatalogType;
684
+ /**
685
+ * 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.
686
+ */
687
+ url?: string;
688
+ feed_format?: FeedFormat;
689
+ update_frequency?: UpdateFrequency;
690
+ /**
691
+ * 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.
692
+ */
693
+ items?: {}[];
694
+ /**
695
+ * Filter catalog to specific item IDs. For offering-type catalogs, these are offering_id values. For product-type catalogs, these are SKU identifiers.
696
+ */
697
+ ids?: string[];
698
+ /**
699
+ * 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'.
700
+ */
701
+ gtins?: string[];
702
+ /**
703
+ * Filter catalog to items with these tags. Tags are matched using OR logic — items matching any tag are included.
704
+ */
705
+ tags?: string[];
706
+ /**
707
+ * Filter catalog to items in this category (e.g., 'beverages/soft-drinks', 'chef-positions').
708
+ */
709
+ category?: string;
710
+ /**
711
+ * Natural language filter for catalog items (e.g., 'all pasta sauces under $5', 'amsterdam vacancies').
712
+ */
713
+ query?: string;
714
+ /**
715
+ * 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.
716
+ */
717
+ conversion_events?: EventType[];
718
+ content_id_type?: ContentIDType;
719
+ /**
720
+ * 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.
721
+ */
722
+ feed_field_mappings?: CatalogFieldMapping[];
723
+ }
724
+
725
+ /**
726
+ * A typed data feed as a creative asset. Carries catalog context (products, stores, jobs, etc.) within the manifest's assets map.
727
+ */
728
+ export interface CatalogAsset {
729
+ /**
730
+ * Buyer's identifier for this catalog. Required when syncing via sync_catalogs. When used in creatives, references a previously synced catalog on the account.
731
+ */
732
+ catalog_id?: string;
733
+ /**
734
+ * Human-readable name for this catalog (e.g., 'Summer Products 2025', 'Amsterdam Store Locations').
735
+ */
736
+ name?: string;
737
+ type: CatalogType;
738
+ /**
739
+ * 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.
740
+ */
741
+ url?: string;
742
+ feed_format?: FeedFormat;
743
+ update_frequency?: UpdateFrequency;
744
+ /**
745
+ * 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.
746
+ */
747
+ items?: {}[];
748
+ /**
749
+ * Filter catalog to specific item IDs. For offering-type catalogs, these are offering_id values. For product-type catalogs, these are SKU identifiers.
750
+ */
751
+ ids?: string[];
752
+ /**
753
+ * 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'.
754
+ */
755
+ gtins?: string[];
756
+ /**
757
+ * Filter catalog to items with these tags. Tags are matched using OR logic — items matching any tag are included.
758
+ */
759
+ tags?: string[];
760
+ /**
761
+ * Filter catalog to items in this category (e.g., 'beverages/soft-drinks', 'chef-positions').
762
+ */
763
+ category?: string;
764
+ /**
765
+ * Natural language filter for catalog items (e.g., 'all pasta sauces under $5', 'amsterdam vacancies').
766
+ */
767
+ query?: string;
768
+ /**
769
+ * 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.
770
+ */
771
+ conversion_events?: EventType[];
772
+ content_id_type?: ContentIDType;
773
+ /**
774
+ * 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.
775
+ */
776
+ feed_field_mappings?: CatalogFieldMapping[];
777
+ /**
778
+ * Discriminator identifying this as a catalog asset. See /schemas/creative/asset-types for the registry.
779
+ */
780
+ asset_type: 'catalog';
781
+ }
782
+
783
+ /**
784
+ * 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).
785
+ */
786
+ export interface CatalogFieldMapping {
787
+ /**
788
+ * Field name in the external feed record. Omit when injecting a static literal value (use the value property instead).
789
+ */
790
+ feed_field?: string;
791
+ /**
792
+ * 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.
793
+ */
794
+ catalog_field?: string;
795
+ /**
796
+ * 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.
797
+ */
798
+ asset_group_id?: string;
799
+ /**
800
+ * 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).
801
+ */
802
+ value?: unknown;
803
+ /**
804
+ * Named transform to apply to the feed field value before writing to the catalog schema. See transform-specific parameters (format, timezone, by, separator).
805
+ */
806
+ transform?: 'date' | 'divide' | 'boolean' | 'split';
807
+ /**
808
+ * 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.
809
+ */
810
+ format?: string;
811
+ /**
812
+ * 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.
813
+ */
814
+ timezone?: string;
815
+ /**
816
+ * For transform 'divide': the divisor to apply (e.g., 100 to convert integer cents to decimal dollars).
817
+ */
818
+ by?: number;
819
+ /**
820
+ * For transform 'split': the separator character or string to split on. Defaults to ','.
821
+ */
822
+ separator?: string;
823
+ /**
824
+ * 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.
825
+ */
826
+ default?: unknown;
827
+ ext?: ExtensionObject;
828
+ }
829
+
830
+ /**
831
+ * 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.
832
+ */
833
+ export type CatalogType = 'offering' | 'product' | 'inventory' | 'store' | 'promotion' | 'hotel' | 'flight' | 'job' | 'vehicle' | 'real_estate' | 'education' | 'destination' | 'app';
834
+
835
+ /**
836
+ * Reference to a collection list for including specific collections (programs, shows) within this product. The package runs on the intersection of matched collections and this list. Use for inclusion-based collection targeting. Seller must declare support in get_adcp_capabilities.
837
+ */
838
+ export interface CollectionListReference {
839
+ /**
840
+ * URL of the agent managing the collection list
841
+ */
842
+ agent_url: string;
843
+ /**
844
+ * Identifier for the collection list within the agent
845
+ * @minLength 1
846
+ */
847
+ list_id: string;
848
+ /**
849
+ * JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access.
850
+ */
851
+ auth_token?: string;
852
+ }
853
+
854
+ /**
855
+ * Trust-source disambiguator for `completion_rate` — *who* attested to the completion event, not *how* (methodology granularity is a separate dimension; future qualifier keys may add it if buyer demand surfaces). The two paths can yield materially different rates, particularly in SSAI environments where the player's view of completion may differ from a vendor's. Used as a `qualifier.completion_source` key on `committed_metrics`, `missing_metrics`, and `metric_aggregates` to disambiguate which trust source the row represents. Edge cases: walled gardens where the seller is also the measurement vendor (YouTube, Spotify) collapse to `seller_attested` by trust-model logic — the same party served and counted. IAB-certified first-party podcast measurement (Podtrac, Triton on their own platforms; Art19 on its own platform) likewise collapses to `seller_attested`. The same vendor's offering on a third-party platform (Podtrac on a publisher who isn't Podtrac) is `vendor_attested`. The trust axis is *not* who runs the SDK — it's who is independent of the seller's revenue interest.
856
+ */
857
+ export type CompletionSource = 'seller_attested' | 'vendor_attested';
858
+
859
+ /**
860
+ * 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.
861
+ */
862
+ 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';
863
+
864
+ /**
865
+ * 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.
866
+ */
867
+ export interface ContextObject {
868
+ }
869
+
870
+ /**
871
+ * Creative asset for upload to library — supports static assets, generative formats, and third-party snippets. Identifies which format this creative conforms to via EITHER a v1 `format_id` (structured `{agent_url, id}`) OR v2 `format_kind` (canonical format name). Mutually exclusive — see the `oneOf` at the schema root.
872
+ */
873
+ export type CreativeAsset = {
874
+ /**
875
+ * Unique identifier for the creative. Stable across v1 and v2 paths — a creative registered against v1 `format_id` retains the same `creative_id` when later viewed via v2 flatten.
876
+ */
877
+ creative_id: string;
878
+ /**
879
+ * Human-readable creative name
880
+ */
881
+ name: string;
882
+ format_id?: FormatReferenceStructuredObject;
883
+ format_kind?: CanonicalFormatKind;
884
+ /**
885
+ * v2 path, optional. Stable identifier matching one of the seller's product `format_options[i].capability_id` values. REQUIRED only when the target product has multiple `format_options` entries sharing the same `format_kind`.
886
+ */
887
+ capability_id?: string;
888
+ /**
889
+ * Assets required by the format, keyed by asset_id. Each slot value is either a single asset object or an array of asset objects (for slots with `min`/`max > 1` like carousel `cards` or responsive_creative `headlines`). Each asset value carries an `asset_type` discriminator that selects the matching asset schema.
890
+ */
891
+ assets: {
892
+ /**
893
+ * This interface was referenced by `undefined`'s JSON-Schema definition
894
+ * via the `patternProperty` "^[a-z0-9_]+$".
895
+ */
896
+ [k: string]: AssetVariant | AssetVariant[];
897
+ };
898
+ /**
899
+ * Preview contexts for generative formats - defines what scenarios to generate previews for
900
+ */
901
+ inputs?: {
902
+ /**
903
+ * Human-readable name for this preview variant
904
+ */
905
+ name: string;
906
+ /**
907
+ * Macro values to apply for this preview
908
+ */
909
+ macros?: {
910
+ [k: string]: string | undefined;
911
+ };
912
+ /**
913
+ * Natural language description of the context for AI-generated content
914
+ */
915
+ context_description?: string;
916
+ }[];
917
+ /**
918
+ * User-defined tags for organization and searchability
919
+ */
920
+ tags?: string[];
921
+ status?: CreativeStatus;
922
+ /**
923
+ * Optional delivery weight for creative rotation when uploading via create_media_buy or update_media_buy (0-100). If omitted, platform determines rotation. Only used during upload to media buy - not stored in creative library.
924
+ * @minimum 0
925
+ * @maximum 100
926
+ */
927
+ weight?: number;
928
+ /**
929
+ * Optional array of placement IDs where this creative should run when uploading via create_media_buy or update_media_buy. References placement_id values from the product's placements array. If omitted, creative runs on all placements. Only used during upload to media buy - not stored in creative library.
930
+ */
931
+ placement_ids?: string[];
932
+ /**
933
+ * Industry-standard identifiers for this creative (e.g., Ad-ID, ISCI, Clearcast clock number). In broadcast buying, these identifiers tie the creative to rotation instructions and traffic systems. A creative may have multiple identifiers when different systems reference the same asset.
934
+ */
935
+ industry_identifiers?: IndustryIdentifier[];
936
+ provenance?: Provenance;
937
+ } & (V1CreativeNamedFormatReference | V2CreativeCanonicalFormatKind);
938
+
939
+ /**
940
+ * Assignment of a creative asset to a package with optional placement targeting. Used in create_media_buy and update_media_buy requests. Note: sync_creatives does not support placement_ids - use create/update_media_buy for placement-level targeting.
941
+ */
942
+ export interface CreativeAssignment {
943
+ /**
944
+ * Unique identifier for the creative
945
+ */
946
+ creative_id: string;
947
+ /**
948
+ * Relative delivery weight for this creative (0–100). When multiple creatives are assigned to the same package, weights determine impression distribution proportionally — a creative with weight 2 gets twice the delivery of weight 1. When omitted, the creative receives equal rotation with other unweighted creatives. A weight of 0 means the creative is assigned but paused (receives no delivery).
949
+ * @minimum 0
950
+ * @maximum 100
951
+ */
952
+ weight?: number;
953
+ /**
954
+ * Optional array of placement IDs where this creative should run. When omitted, the creative runs on all placements in the package. References placement_id values from the product's placements array.
955
+ */
956
+ placement_ids?: string[];
957
+ }
958
+
959
+ /**
960
+ * 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.
961
+ */
962
+ export type CreativeIdentifierType = 'ad_id' | 'isci' | 'clearcast_clock';
963
+
964
+ /**
965
+ * For generative creatives: set to 'approved' to finalize, 'rejected' to request regeneration with updated assets/message. Omit for non-generative creatives (system will set based on processing state).
966
+ */
967
+ export type CreativeStatus = 'processing' | 'pending_review' | 'approved' | 'rejected' | 'archived';
968
+
969
+ /**
970
+ * DAAST (Digital Audio Ad Serving Template) tag for third-party audio ad serving
971
+ */
972
+ export type DAASTAsset = {
973
+ /**
974
+ * Discriminator identifying this as a DAAST asset. See /schemas/creative/asset-types for the registry.
975
+ */
976
+ asset_type: 'daast';
977
+ daast_version?: DAASTVersion;
978
+ /**
979
+ * Expected audio duration in milliseconds (if known)
980
+ * @minimum 0
981
+ */
982
+ duration_ms?: number;
983
+ /**
984
+ * Tracking events supported by this DAAST tag
985
+ */
986
+ tracking_events?: DAASTTrackingEvent[];
987
+ /**
988
+ * Whether companion display ads are included
989
+ */
990
+ companion_ads?: boolean;
991
+ /**
992
+ * URL to text transcript of the audio content
993
+ */
994
+ transcript_url?: string;
995
+ provenance?: Provenance;
996
+ } & ({
997
+ /**
998
+ * Discriminator indicating DAAST is delivered via URL endpoint
999
+ */
1000
+ delivery_type: 'url';
1001
+ /**
1002
+ * URL endpoint that returns DAAST XML
1003
+ */
1004
+ url: string;
1005
+ } | {
1006
+ /**
1007
+ * Discriminator indicating DAAST is delivered as inline XML content
1008
+ */
1009
+ delivery_type: 'inline';
1010
+ /**
1011
+ * Inline DAAST XML content
1012
+ */
1013
+ content: string;
1014
+ });
1015
+
1016
+ /**
1017
+ * 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`.
1018
+ */
1019
+ 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';
1020
+
1021
+ /**
1022
+ * DAAST specification version
1023
+ */
1024
+ export type DAASTVersion = '1.0' | '1.1';
1025
+
1026
+ /**
1027
+ * Days of the week for daypart targeting
1028
+ */
1029
+ export type DayOfWeek = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
1030
+
1031
+ /**
1032
+ * A time window for daypart targeting. Specifies days of week and an hour range. start_hour is inclusive, end_hour is exclusive (e.g., 6-10 = 6:00am to 10:00am). Follows the Google Ads AdScheduleInfo / DV360 DayPartTargeting pattern.
1033
+ */
1034
+ export interface DaypartTarget {
1035
+ /**
1036
+ * Days of week this window applies to. Use multiple days for compact targeting (e.g., monday-friday in one object).
1037
+ */
1038
+ days: DayOfWeek[];
1039
+ /**
1040
+ * Start hour (inclusive), 0-23 in 24-hour format. 0 = midnight, 6 = 6:00am, 18 = 6:00pm.
1041
+ * @minimum 0
1042
+ * @maximum 23
1043
+ */
1044
+ start_hour: number;
1045
+ /**
1046
+ * End hour (exclusive), 1-24 in 24-hour format. 10 = 10:00am, 24 = midnight. Must be greater than start_hour.
1047
+ * @minimum 1
1048
+ * @maximum 24
1049
+ */
1050
+ end_hour: number;
1051
+ /**
1052
+ * Optional human-readable name for this time window (e.g., 'Morning Drive', 'Prime Time')
1053
+ */
1054
+ label?: string;
1055
+ }
1056
+
1057
+ /**
1058
+ * Operating system platforms for device targeting. Browser values from Sec-CH-UA-Platform standard, extended for CTV.
1059
+ */
1060
+ export type DevicePlatform = 'ios' | 'android' | 'windows' | 'macos' | 'linux' | 'chromeos' | 'tvos' | 'tizen' | 'webos' | 'fire_os' | 'roku_os' | 'unknown';
1061
+
1062
+ /**
1063
+ * Device form factor categories for targeting and reporting. Complements device-platform (operating system) with hardware classification. OpenRTB mapping: 1 (Mobile/Tablet General) → mobile, 2 (PC) → desktop, 4 (Phone) → mobile, 5 (Tablet) → tablet, 6 (Connected Device) → ctv, 7 (Set Top Box) → ctv. DOOH inventory uses dooh.
1064
+ */
1065
+ export type DeviceType = 'desktop' | 'mobile' | 'tablet' | 'ctv' | 'dooh' | 'unknown';
1066
+
1067
+ /**
1068
+ * IPTC-aligned classification of AI involvement in producing this content
1069
+ */
1070
+ 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';
1071
+
1072
+ /**
1073
+ * How long the disclosure must persist during content playback or display
1074
+ */
1075
+ export type DisclosurePersistence = 'continuous' | 'initial' | 'flexible';
1076
+
1077
+ /**
1078
+ * 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.
1079
+ */
1080
+ export type DisclosurePosition = 'prominent' | 'footer' | 'audio' | 'subtitle' | 'overlay' | 'end_card' | 'pre_roll' | 'companion';
1081
+
1082
+ /**
1083
+ * 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.
1084
+ */
1085
+ export interface Duration {
1086
+ /**
1087
+ * Number of time units. Must be 1 when unit is 'campaign'.
1088
+ * @minimum 1
1089
+ */
1090
+ interval: number;
1091
+ /**
1092
+ * Time unit. 'seconds' for sub-minute precision. 'campaign' spans the full campaign flight.
1093
+ */
1094
+ unit: 'seconds' | 'minutes' | 'hours' | 'days' | 'campaign';
1095
+ }
1096
+
1097
+ /**
1098
+ * How provenance data is carried within the content
1099
+ */
1100
+ export type EmbeddedProvenanceMethod = 'manifest_wrapper' | 'provenance_markers';
1101
+
1102
+ /**
1103
+ * Standard marketing event types for event logging, aligned with IAB ECAPI
1104
+ */
1105
+ 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';
1106
+
1107
+ /**
1108
+ * 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.
1109
+ */
1110
+ export interface ExtensionObject {
1111
+ }
1112
+
1113
+ /**
1114
+ * 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.
1115
+ */
1116
+ export type FeedFormat = 'google_merchant_center' | 'facebook_catalog' | 'shopify' | 'linkedin_jobs' | 'custom';
1117
+
1118
+ /**
1119
+ * 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.
1120
+ */
1121
+ export interface FormatReferenceStructuredObject {
1122
+ /**
1123
+ * 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.
1124
+ */
1125
+ agent_url: string;
1126
+ /**
1127
+ * 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.
1128
+ * @pattern ^[a-zA-Z0-9_-]+$
1129
+ */
1130
+ id: string;
1131
+ /**
1132
+ * 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.
1133
+ * @minimum 1
1134
+ */
1135
+ width?: number;
1136
+ /**
1137
+ * 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.
1138
+ * @minimum 1
1139
+ */
1140
+ height?: number;
1141
+ /**
1142
+ * Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.
1143
+ * @minimum 1
1144
+ */
1145
+ duration_ms?: number;
1146
+ }
1147
+
1148
+ /**
1149
+ * Whether the video uses a constant or variable frame rate. Broadcast and SSAI contexts require constant frame rate for seamless splicing.
1150
+ */
1151
+ export type FrameRateType = 'constant' | 'variable';
1152
+
1153
+ /**
1154
+ * Frequency capping settings for package-level application. Two types of frequency control can be used independently or together: suppress enforces a cooldown between consecutive exposures; max_impressions + per + window caps total exposures per entity in a time window. When both suppress and max_impressions are set, an impression is delivered only if both constraints permit it (AND semantics). At least one of suppress, suppress_minutes, or max_impressions must be set.
1155
+ */
1156
+ export type FrequencyCap = {
1157
+ [k: string]: unknown | undefined;
1158
+ } & {
1159
+ /**
1160
+ * Cooldown period between consecutive exposures to the same entity. Prevents back-to-back ad delivery (e.g. {"interval": 60, "unit": "minutes"} for a 1-hour cooldown). Preferred over suppress_minutes.
1161
+ */
1162
+ suppress?: Duration;
1163
+ /**
1164
+ * Deprecated — use suppress instead. Cooldown period in minutes between consecutive exposures to the same entity (e.g. 60 for a 1-hour cooldown).
1165
+ * @minimum 0
1166
+ */
1167
+ suppress_minutes?: number;
1168
+ /**
1169
+ * Maximum number of impressions per entity per window. For duration windows, implementations typically use a rolling window; 'campaign' applies a fixed cap across the full flight.
1170
+ * @minimum 1
1171
+ */
1172
+ max_impressions?: number;
1173
+ /**
1174
+ * Entity granularity for impression counting. Required when max_impressions is set.
1175
+ */
1176
+ per?: ReachUnit;
1177
+ /**
1178
+ * Time window for the max_impressions cap (e.g. {"interval": 7, "unit": "days"} or {"interval": 1, "unit": "campaign"} for the full flight). Required when max_impressions is set.
1179
+ */
1180
+ window?: Duration;
1181
+ };
1182
+
1183
+ /**
1184
+ * Group of Pictures structure. SSAI and broadcast require closed GOPs for clean splice points; open GOPs may produce artifacts at ad boundaries.
1185
+ */
1186
+ export type GOPType = 'closed' | 'open';
1187
+
1188
+ /**
1189
+ * 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.
1190
+ */
1191
+ export interface HTMLAsset {
1192
+ /**
1193
+ * Discriminator identifying this as an HTML asset. See /schemas/creative/asset-types for the registry.
1194
+ */
1195
+ asset_type: 'html';
1196
+ /**
1197
+ * HTML content
1198
+ */
1199
+ content: string;
1200
+ /**
1201
+ * HTML version (e.g., 'HTML5')
1202
+ */
1203
+ version?: string;
1204
+ /**
1205
+ * Self-declared accessibility properties for this opaque creative
1206
+ */
1207
+ accessibility?: {
1208
+ /**
1209
+ * Text alternative describing the creative content
1210
+ */
1211
+ alt_text?: string;
1212
+ /**
1213
+ * Whether the creative can be fully operated via keyboard
1214
+ */
1215
+ keyboard_navigable?: boolean;
1216
+ /**
1217
+ * Whether the creative respects prefers-reduced-motion or provides pause/stop controls
1218
+ */
1219
+ motion_control?: boolean;
1220
+ /**
1221
+ * Whether the creative has been tested with screen readers
1222
+ */
1223
+ screen_reader_tested?: boolean;
1224
+ };
1225
+ provenance?: Provenance;
1226
+ }
1227
+
1228
+ /**
1229
+ * HTTP method
1230
+ */
1231
+ export type HTTPMethod = 'GET' | 'POST';
1232
+
1233
+ /**
1234
+ * Override logo asset.
1235
+ */
1236
+ export interface ImageAsset {
1237
+ /**
1238
+ * Discriminator identifying this as an image asset. See /schemas/creative/asset-types for the registry.
1239
+ */
1240
+ asset_type: 'image';
1241
+ /**
1242
+ * URL to the image asset
1243
+ */
1244
+ url: string;
1245
+ /**
1246
+ * Width in pixels
1247
+ * @minimum 1
1248
+ */
1249
+ width: number;
1250
+ /**
1251
+ * Height in pixels
1252
+ * @minimum 1
1253
+ */
1254
+ height: number;
1255
+ /**
1256
+ * Image file format (jpg, png, gif, webp, etc.)
1257
+ */
1258
+ format?: string;
1259
+ /**
1260
+ * Alternative text for accessibility
1261
+ */
1262
+ alt_text?: string;
1263
+ provenance?: Provenance;
1264
+ }
1265
+
1266
+ /**
1267
+ * 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.
1268
+ */
1269
+ export interface IndustryIdentifier {
1270
+ type: CreativeIdentifierType;
1271
+ /**
1272
+ * The identifier value (e.g., 'ABCD1234000H' for Ad-ID)
1273
+ * @maxLength 64
1274
+ */
1275
+ value: string;
1276
+ }
1277
+
1278
+ /**
1279
+ * 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.
1280
+ */
1281
+ export interface JavaScriptAsset {
1282
+ /**
1283
+ * Discriminator identifying this as a JavaScript asset. See /schemas/creative/asset-types for the registry.
1284
+ */
1285
+ asset_type: 'javascript';
1286
+ /**
1287
+ * JavaScript content
1288
+ */
1289
+ content: string;
1290
+ module_type?: JavaScriptModuleType;
1291
+ /**
1292
+ * Self-declared accessibility properties for this opaque creative
1293
+ */
1294
+ accessibility?: {
1295
+ /**
1296
+ * Text alternative describing the creative content
1297
+ */
1298
+ alt_text?: string;
1299
+ /**
1300
+ * Whether the creative can be fully operated via keyboard
1301
+ */
1302
+ keyboard_navigable?: boolean;
1303
+ /**
1304
+ * Whether the creative respects prefers-reduced-motion or provides pause/stop controls
1305
+ */
1306
+ motion_control?: boolean;
1307
+ /**
1308
+ * Whether the creative has been tested with screen readers
1309
+ */
1310
+ screen_reader_tested?: boolean;
1311
+ };
1312
+ provenance?: Provenance;
1313
+ }
1314
+
1315
+ /**
1316
+ * JavaScript module type
1317
+ */
1318
+ export type JavaScriptModuleType = 'esm' | 'commonjs' | 'script';
1319
+
1320
+ /**
1321
+ * Brand-lift dimension disambiguator. Brand lift is multidimensional in production — Kantar, Upwave, Cint, DoubleVerify, and similar vendors report awareness, consideration, favorability, purchase intent, and ad recall as separate measurements with their own sample sizes and confidence intervals. Used as a `qualifier.lift_dimension` key on `committed_metrics`, `missing_metrics`, `metric_aggregates`, and `performance-feedback.metric` to disambiguate which dimension of `brand_lift` a row represents. Two `brand_lift` rows under different lift dimensions represent different surveyed outcomes and must not be combined into a single number.
1322
+ */
1323
+ export type LiftDimension = 'awareness' | 'consideration' | 'favorability' | 'purchase_intent' | 'ad_recall';
1324
+
1325
+ /**
1326
+ * Remedy types available when a performance standard or billing measurement threshold is breached.
1327
+ */
1328
+ export type MakegoodRemedy = 'additional_delivery' | 'credit' | 'invoice_adjustment';
1329
+
1330
+ /**
1331
+ * Markdown-formatted text content following CommonMark specification
1332
+ */
1333
+ export interface MarkdownAsset {
1334
+ /**
1335
+ * Discriminator identifying this as a markdown asset. See /schemas/creative/asset-types for the registry.
1336
+ */
1337
+ asset_type: 'markdown';
1338
+ /**
1339
+ * Markdown content following CommonMark spec with optional GitHub Flavored Markdown extensions
1340
+ */
1341
+ content: string;
1342
+ /**
1343
+ * Language code (e.g., 'en', 'es', 'fr')
1344
+ */
1345
+ language?: string;
1346
+ markdown_flavor?: MarkdownFlavor;
1347
+ /**
1348
+ * Whether raw HTML blocks are allowed in the markdown. False recommended for security.
1349
+ */
1350
+ allow_raw_html?: boolean;
1351
+ }
1352
+
1353
+ /**
1354
+ * Markdown flavor used. CommonMark for strict compatibility, GFM for tables/task lists/strikethrough.
1355
+ */
1356
+ export type MarkdownFlavor = 'commonmark' | 'gfm';
1357
+
1358
+ /**
1359
+ * Keyword targeting match type. broad: ads may serve on queries semantically related to the keyword. phrase: ads serve when the query contains the keyword phrase. exact: ads serve only when the query matches the keyword exactly.
1360
+ */
1361
+ export type MatchType = 'broad' | 'phrase' | 'exact';
1362
+
1363
+ /**
1364
+ * Seller's default billing measurement and makegood terms. Declares who counts the billing metric and what remedies apply when thresholds are breached. Buyers may propose different terms at media buy creation — sellers accept, reject (TERMS_REJECTED), or adjust per their policy.
1365
+ */
1366
+ export interface MeasurementTerms {
1367
+ /**
1368
+ * Which vendor's count of the billing metric governs invoicing. The billing metric is determined by the pricing_model on the selected pricing_option (e.g., impressions for CPM, completed views for CPCV).
1369
+ */
1370
+ billing_measurement?: {
1371
+ vendor: BrandReference;
1372
+ /**
1373
+ * Maximum acceptable variance between the billing vendor's count and the other party's count before resolution is triggered (e.g., 10 means a 10% divergence triggers review).
1374
+ * @minimum 0
1375
+ */
1376
+ max_variance_percent?: number;
1377
+ /**
1378
+ * Which measurement maturation stage the billing metric is reconciled against. References a window_id from the product's reporting_capabilities.measurement_windows. Examples: 'c7' for broadcast TV guarantees (live + 7 days DVR), 'final' for DOOH after IVT/fraud-check processing, 'post_sivt' for digital after sophisticated invalid-traffic filtering, 'downloads_30d' for podcast. When absent, billing is based on the seller's standard reporting without windowed maturation.
1379
+ */
1380
+ measurement_window?: string;
1381
+ /**
1382
+ * Maximum hours by which the authoritative party MUST publish a final record (`is_final: true` / `finalized_at` on `get_media_buy_delivery`, or `final: true` / `finalized_at` on `report_usage`). **Anchor:** when `measurement_window` is set, hours are counted from the close of that window (e.g., 240h after `c7` close = ~10 days after the 7-day DVR accumulation completes); when `measurement_window` is absent, hours are counted from `reporting_period.end`. Picking a single anchor avoids ambiguity for windowed channels where `reporting_period.end` and window close differ by days. The deadline applies to whichever party is named in `vendor` — seller, buyer, or third-party vendor — symmetrically. When the deadline elapses without a final record, the counterparty MAY fall back to its own attestation for invoicing (seller falls back to seller-attested numbers via `get_media_buy_delivery`; buyer falls back to a buyer-attested `report_usage` push), and the breach is treated like any other measurement-terms breach under `makegood_policy`. Absent means no contractual deadline — finalization is best-effort and disagreements resolve out of band.
1383
+ * @minimum 0
1384
+ */
1385
+ finalization_deadline_hours?: number;
1386
+ };
1387
+ /**
1388
+ * Remedies available when a performance standard or billing measurement variance is breached. Seller declares which remedy types they support. When a breach occurs, the seller proposes a remedy from this menu; the buyer accepts or disputes.
1389
+ */
1390
+ makegood_policy?: {
1391
+ /**
1392
+ * Remedy types the seller supports. Ordered by seller preference (first = preferred). Seller proposes from this list when a breach occurs; buyer accepts or disputes.
1393
+ */
1394
+ available_remedies: MakegoodRemedy[];
1395
+ };
1396
+ }
1397
+
1398
+ /**
1399
+ * How a seller honors a given action on a media buy. Buyers branch on this to decide whether to expect a synchronous response, an automatic-with-fallback flow, a proposal lifecycle round-trip, or an asynchronous human approval. The mode is declared on each entry of `allowed_actions[]` (product, as `modes[]` array) or `available_actions[]` (buy, as singular `mode`).
1400
+ */
1401
+ export type MediaBuyActionMode = 'self_serve' | 'conditional_self_serve' | 'requires_proposal' | 'requires_approval';
1402
+
1403
+ /**
1404
+ * An action currently available on a media buy, resolved against the buy's current status, negotiated terms, account tier, and any buy-level overrides. Authoritative per-buy capability — buyer SDKs MUST read this rather than re-deriving from the product's `allowed_actions[]`, because divergence from the product template is expected (negotiated terms and IO addenda live on the deal, not the product SKU). The containing `available_actions[]` array is uniquely keyed by `action`; sellers MUST NOT emit two entries with the same `action` value (this is a contract-level invariant — JSON Schema `uniqueItems` only catches structurally identical objects, so validators MUST enforce action-uniqueness separately). Predicate evaluators consuming dotted paths like `available_actions.extend_flight.sla.response_max` MUST index by `action` rather than by array position. The `mode` and `sla` values are advisory at the moment of emission; sellers MAY resolve to a different mode by the time the mutation arrives (state can change), in which case the request is rejected with `ACTION_NOT_ALLOWED` (`reason: mode_mismatch`).
1405
+ */
1406
+ export interface MediaBuyAvailableAction {
1407
+ action: MediaBuyValidAction;
1408
+ mode: MediaBuyActionMode;
1409
+ sla?: SLAWindow;
1410
+ /**
1411
+ * Optional pointer into buy-terms negotiation (forward-references the buy-terms namespace landing via separate RFC). Schema accepts any string for now and will tighten to a structured reference when the buy-terms RFC ships.
1412
+ */
1413
+ terms_ref?: string;
1414
+ }
1415
+
1416
+ /**
1417
+ * Status of a media buy.
1418
+ */
1419
+ export type MediaBuyStatus = 'pending_creatives' | 'pending_start' | 'active' | 'paused' | 'completed' | 'rejected' | 'canceled';
1420
+
1421
+ /**
1422
+ * The action identifier.
1423
+ */
1424
+ export type MediaBuyValidAction = 'pause' | 'resume' | 'cancel' | 'extend_flight' | 'shorten_flight' | 'update_flight_dates' | 'increase_budget' | 'decrease_budget' | 'reallocate_budget' | 'update_targeting' | 'update_pacing' | 'update_frequency_caps' | 'replace_creative' | 'update_creative_assignments' | 'remove_creative' | 'add_packages' | 'remove_packages' | 'update_budget' | 'update_dates' | 'update_packages' | 'sync_creatives';
1425
+
1426
+ /**
1427
+ * Metro classification system
1428
+ */
1429
+ export type MetroAreaSystem = 'nielsen_dma' | 'uk_itl1' | 'uk_itl2' | 'eurostat_nuts2' | 'custom';
1430
+
1431
+ /**
1432
+ * Position of the moov atom in an MP4 container. 'start' enables progressive download without buffering the entire file; required for streaming ad delivery.
1433
+ */
1434
+ export type MoovAtomPosition = 'start' | 'end';
1435
+
1436
+ /**
1437
+ * A single optimization target for a package. Packages accept an array of optimization_goals. When multiple goals are present, priority determines which the seller focuses on — 1 is highest priority (primary goal); higher numbers are secondary. Duplicate priority values result in undefined seller behavior.
1438
+ */
1439
+ export type OptimizationGoal = {
1440
+ kind: 'metric';
1441
+ /**
1442
+ * Seller-native metric to optimize for. Delivery metrics: clicks (link clicks, swipe-throughs, CTA taps that navigate away), views (viewable impressions), completed_views (video/audio completions — see view_duration_seconds), reach (unique audience reach — see reach_unit and target_frequency). Duration/score metrics: viewed_seconds (time in view per impression — reported back via `delivery-metrics.viewability.viewed_seconds`, governed by the viewability `standard`). Audience action metrics: engagements (any direct interaction with the ad unit beyond viewing — social reactions/comments/shares, story/unit opens, interactive overlay taps, companion banner interactions on audio and CTV), follows (new followers, page likes, artist/podcast/channel subscribes), saves (saves, bookmarks, playlist adds, pins — signals of intent to return), profile_visits (visits to the brand's in-platform page — profile, artist page, channel, or storefront. Does not include external website clicks, which are covered by 'clicks'). **DEPRECATED values** (slated for removal at next major): `attention_seconds` and `attention_score` — these have no industry-graduated definition (DoubleVerify, IAS, Adelaide, TVision, Lumen each define them differently) and cannot be meaningfully optimized for without a vendor binding. Use `kind: 'vendor_metric'` with an explicit `vendor` and `metric_id` instead — that path binds the goal to a specific measurement vendor and reconciles to the same `(vendor, metric_id)` key in delivery's `vendor_metric_values[]`. Sellers MAY reject the deprecated values with `TERMS_REJECTED` and a suggestion to use the `vendor_metric` kind.
1443
+ */
1444
+ metric: 'clicks' | 'views' | 'completed_views' | 'viewed_seconds' | 'attention_seconds' | 'attention_score' | 'engagements' | 'follows' | 'saves' | 'profile_visits' | 'reach';
1445
+ /**
1446
+ * Unit for reach measurement. Required when metric is 'reach'. Must be a value declared in the product's metric_optimization.supported_reach_units.
1447
+ */
1448
+ reach_unit?: ReachUnit;
1449
+ /**
1450
+ * Target frequency band for reach optimization. Only applicable when metric is 'reach'. Frames frequency as an optimization signal: the seller should treat impressions toward entities already within the [min, max] band as lower-value, and impressions toward unreached entities as higher-value. This shifts budget toward fresh reach rather than re-reaching known users. When omitted, the seller maximizes unique reach without a frequency constraint. A hard cap can still be layered via targeting_overlay.frequency_cap if a ceiling is needed.
1451
+ */
1452
+ target_frequency?: {
1453
+ [k: string]: unknown | undefined;
1454
+ };
1455
+ /**
1456
+ * Minimum video view duration in seconds that qualifies as a completed_view for this goal. Only applicable when metric is 'completed_views'. When omitted, the seller uses their platform default (typically 2–15 seconds). Common values: 2 (Snap/LinkedIn default), 6 (TikTok), 15 (Snap 15-second views, Meta ThruPlay). Sellers declare which durations they support in metric_optimization.supported_view_durations. Sellers must reject goals with unsupported values — silent rounding would create measurement discrepancies.
1457
+ */
1458
+ view_duration_seconds?: number;
1459
+ /**
1460
+ * Target for this metric. When omitted, the seller optimizes for maximum metric volume within budget.
1461
+ */
1462
+ target?: {
1463
+ kind: 'cost_per';
1464
+ /**
1465
+ * Target cost per metric unit in the buy currency
1466
+ */
1467
+ value: number;
1468
+ } | {
1469
+ kind: 'threshold_rate';
1470
+ /**
1471
+ * Minimum per-impression value. Units depend on the metric: proportion (clicks, views, completed_views), seconds (viewed_seconds, attention_seconds), or score (attention_score).
1472
+ */
1473
+ value: number;
1474
+ };
1475
+ /**
1476
+ * Relative priority among all optimization goals on this package. 1 = highest priority (primary goal); higher numbers are lower priority (secondary signals). When omitted, sellers may use array position as priority.
1477
+ * @minimum 1
1478
+ */
1479
+ priority?: number;
1480
+ } | {
1481
+ kind: 'event';
1482
+ /**
1483
+ * Event source and type pairs that feed this goal. Each entry identifies a source and event type to include. When the seller supports multi_source_event_dedup (declared in get_adcp_capabilities), they deduplicate by event_id across all entries — the same business event from multiple sources counts once, using value_field and value_factor from the first matching entry. When multi_source_event_dedup is false or absent, buyers should use a single entry per goal; the seller will use only the first entry. All event sources must be configured via sync_event_sources.
1484
+ */
1485
+ event_sources: {
1486
+ /**
1487
+ * Event source to include (must be configured on this account via sync_event_sources)
1488
+ * @minLength 1
1489
+ */
1490
+ event_source_id: string;
1491
+ event_type: EventType;
1492
+ /**
1493
+ * Required when event_type is 'custom'. Platform-specific name for the custom event.
1494
+ */
1495
+ custom_event_name?: string;
1496
+ /**
1497
+ * Which field in the event's custom_data carries the monetary value. The seller must use this field for value extraction and aggregation when computing ROAS and conversion value metrics. Required on at least one entry when target.kind is 'per_ad_spend' or 'maximize_value' — sellers must reject these target kinds when no event source entry includes value_field. When present without a value-oriented target, the seller may use it for delivery reporting (conversion_value, roas) but must not change the optimization objective. Common values: 'value', 'order_total', 'profit_margin'. This is not passed as a parameter to underlying platform APIs — the seller maps it to their platform's value ingestion mechanism.
1498
+ */
1499
+ value_field?: string;
1500
+ /**
1501
+ * Multiplier the seller must apply to value_field before aggregation. Use -1 for refund events (negate the value), 0.01 for values in cents, -0.01 for refunds in cents. A value of 0 zeroes out this source's value contribution (the source still counts for event dedup). Defaults to 1. This is not passed as a parameter to underlying platform APIs — the seller applies it when computing aggregated value metrics.
1502
+ */
1503
+ value_factor?: number;
1504
+ }[];
1505
+ /**
1506
+ * Target cost or return for this event goal. When omitted, the seller optimizes for maximum conversion count within budget — regardless of whether value_field is present on event sources. The presence of value_field alone does not change the optimization objective; it only makes value available for reporting. An explicit target of maximize_value or per_ad_spend is required to steer toward value.
1507
+ */
1508
+ target?: {
1509
+ kind: 'cost_per';
1510
+ /**
1511
+ * Target cost per event in the buy currency
1512
+ */
1513
+ value: number;
1514
+ } | {
1515
+ kind: 'per_ad_spend';
1516
+ /**
1517
+ * Target return ratio (e.g., 4.0 means $4 of value per $1 spent)
1518
+ */
1519
+ value: number;
1520
+ } | {
1521
+ kind: 'maximize_value';
1522
+ };
1523
+ /**
1524
+ * Attribution window for this optimization goal — references the canonical `attribution-window` shape (post_click, post_view, model). Values must match an option declared in the seller's `conversion_tracking.attribution_windows` capability. Sellers MUST reject windows not in their declared capabilities. When the entire field is omitted, the seller uses their default window.
1525
+ */
1526
+ attribution_window?: AttributionWindow;
1527
+ /**
1528
+ * Relative priority among all optimization goals on this package. 1 = highest priority (primary goal); higher numbers are lower priority (secondary signals). When omitted, sellers may use array position as priority.
1529
+ * @minimum 1
1530
+ */
1531
+ priority?: number;
1532
+ } | {
1533
+ kind: 'vendor_metric';
1534
+ vendor: BrandReference;
1535
+ metric_id: VendorMetricID;
1536
+ /**
1537
+ * Target for this vendor metric. When omitted, the seller optimizes for maximum metric volume / score within budget. `cost_per` and `threshold_rate` semantics mirror the same target kinds on the `metric` kind — units are vendor-defined and depend on the vendor's `measurement.metrics[]` declaration for this `metric_id`.
1538
+ */
1539
+ target?: {
1540
+ kind: 'cost_per';
1541
+ /**
1542
+ * Target cost per metric unit in the buy currency. Units of the metric are vendor-defined.
1543
+ */
1544
+ value: number;
1545
+ } | {
1546
+ kind: 'threshold_rate';
1547
+ /**
1548
+ * Minimum per-impression value. Units of the metric are vendor-defined.
1549
+ */
1550
+ value: number;
1551
+ };
1552
+ /**
1553
+ * Relative priority among all optimization goals on this package. 1 = highest priority (primary goal); higher numbers are lower priority (secondary signals). When omitted, sellers may use array position as priority.
1554
+ * @minimum 1
1555
+ */
1556
+ priority?: number;
1557
+ };
1558
+
1559
+ /**
1560
+ * Budget pacing strategy
1561
+ */
1562
+ export type Pacing = 'even' | 'asap' | 'front_loaded';
1563
+
1564
+ /**
1565
+ * A specific product within a media buy (line item)
1566
+ */
1567
+ export interface Package {
1568
+ /**
1569
+ * Seller's unique identifier for the package
1570
+ */
1571
+ package_id: string;
1572
+ /**
1573
+ * ID of the product this package is based on
1574
+ */
1575
+ product_id?: string;
1576
+ /**
1577
+ * Budget allocation for this package in the currency specified by the pricing option
1578
+ * @minimum 0
1579
+ */
1580
+ budget?: number;
1581
+ pacing?: Pacing;
1582
+ /**
1583
+ * ID of the selected pricing option from the product's pricing_options array
1584
+ */
1585
+ pricing_option_id?: string;
1586
+ /**
1587
+ * Bid price for auction-based pricing. This is the exact bid/price to honor unless the selected pricing option has max_bid=true, in which case bid_price is the buyer's maximum willingness to pay (ceiling).
1588
+ * @minimum 0
1589
+ */
1590
+ bid_price?: number;
1591
+ price_breakdown?: PriceBreakdown;
1592
+ /**
1593
+ * Impression goal for this package
1594
+ * @minimum 0
1595
+ */
1596
+ impressions?: number;
1597
+ /**
1598
+ * Catalogs this package promotes. Each catalog MUST have a distinct type (e.g., one product catalog, one store catalog). This constraint is enforced at the application level — sellers MUST reject requests containing multiple catalogs of the same type with a validation_error. Echoed from the create_media_buy request.
1599
+ */
1600
+ catalogs?: Catalog[];
1601
+ /**
1602
+ * Format IDs active for this package. Echoed from the create_media_buy request; omitted means all formats for the product are active.
1603
+ */
1604
+ format_ids?: FormatReferenceStructuredObject[];
1605
+ targeting_overlay?: TargetingOverlay;
1606
+ measurement_terms?: MeasurementTerms;
1607
+ /**
1608
+ * Agreed performance standards for this package. When any entry specifies a vendor, creatives assigned to this package MUST include corresponding tracker_script or tracker_pixel assets from that vendor.
1609
+ */
1610
+ performance_standards?: PerformanceStandard[];
1611
+ /**
1612
+ * The binding reporting contract for this package — what the seller has agreed to populate in delivery reports. Each entry carries an explicit `committed_at` timestamp, so the array also serves as the contract amendment ledger: day-1 commitments share `committed_at = create_media_buy.confirmed_at`; mid-flight additions carry their own timestamps. The `missing_metrics` field on `get_media_buy_delivery` reconciles against this list, filtering to entries where `committed_at < reporting_period.end` (a metric committed mid-flight is only audited from its commitment timestamp forward). Sellers stamp the day-1 set on the `create_media_buy` response; mid-flight additions are appended via `update_media_buy` (append-only — sellers MUST reject attempts to modify or remove existing entries with `validation_error`, suggested code: `IMMUTABLE_FIELD`). Optional in v1; absence means the seller does not provide an audit-grade contract and `missing_metrics` falls back to the product's live `available_metrics` (a known audit gap — buyers SHOULD treat absence as 'no audit-grade contract' rather than 'clean delivery'). Each entry uses an explicit `scope` discriminator: `standard` for entries from the closed `available-metric.json` enum, `vendor` for vendor-defined metrics anchored on a BrandRef. The unified shape is symmetric with `missing_metrics` and `aggregated_totals.metric_aggregates` — same atomic unit `(scope, metric_id, qualifier)` across contract, diff, and delivery, so reconciliation collapses to a row-level join on the tuple. Replaces the parallel-array design that shipped briefly in #3510.
1613
+ */
1614
+ committed_metrics?: ({
1615
+ /**
1616
+ * Standard metric from the closed `available-metric.json` enum.
1617
+ */
1618
+ scope: 'standard';
1619
+ metric_id: AvailableMetric;
1620
+ /**
1621
+ * Disambiguates metrics whose definition varies by qualifier. Today carries five keys — `viewability_standard` (MRC vs GroupM viewability), `completion_source` (seller- vs vendor-attested completion), `attribution_methodology` (how attribution was computed for outcome metrics), `attribution_window` (the time window over which outcomes were attributed), and `lift_dimension` (which dimension of brand_lift this row represents — awareness, consideration, etc.). Required when the underlying `metric_id` has multiple incompatible measurement paths AND the seller commits to a specific one. Symmetric on `missing_metrics`. Reserved for additive qualifiers in future minors — schema is closed (`additionalProperties: false`); new keys ship explicitly. **Heterogeneous value types**: qualifier values can be either string enums (`viewability_standard`, `completion_source`, `attribution_methodology`, `lift_dimension`) or structured objects (`attribution_window` is a duration `{interval, unit}`). Consumers MUST dispatch on key name to know value shape; structured-value qualifiers join on canonical (key-sorted) deep equality so `{interval: 14, unit: 'days'}` and `{unit: 'days', interval: 14}` resolve to the same partition. Rate-style metrics (`new_to_brand_rate`, `engagement_rate`, etc.) inherit the methodology of their numerator — when a rate carries `attribution_methodology` qualifier, it applies to the underlying conversions/events being rated.
1622
+ */
1623
+ qualifier?: {
1624
+ viewability_standard?: ViewabilityStandard;
1625
+ completion_source?: CompletionSource;
1626
+ attribution_methodology?: AttributionMethodology;
1627
+ attribution_window?: Duration;
1628
+ lift_dimension?: LiftDimension;
1629
+ };
1630
+ /**
1631
+ * ISO 8601 timestamp when this metric became part of the contract. Day-1 commitments use `create_media_buy.confirmed_at`; mid-flight additions use the time the amendment was accepted.
1632
+ * @format date-time
1633
+ */
1634
+ committed_at: string;
1635
+ } | {
1636
+ /**
1637
+ * Vendor-defined metric, identified by the tuple `(vendor, metric_id)`.
1638
+ */
1639
+ scope: 'vendor';
1640
+ vendor: BrandReference;
1641
+ metric_id: VendorMetricID;
1642
+ /**
1643
+ * ISO 8601 timestamp when this vendor metric became part of the contract.
1644
+ * @format date-time
1645
+ */
1646
+ committed_at: string;
1647
+ })[];
1648
+ /**
1649
+ * Creative assets assigned to this package
1650
+ */
1651
+ creative_assignments?: CreativeAssignment[];
1652
+ /**
1653
+ * Format IDs that creative assets will be provided for this package
1654
+ */
1655
+ format_ids_to_provide?: FormatReferenceStructuredObject[];
1656
+ /**
1657
+ * Optimization targets for this package. The seller optimizes delivery toward these goals in priority order. Common pattern: event goals (purchase, install) as primary targets at priority 1; metric goals (clicks, views) as secondary proxy signals at priority 2+.
1658
+ */
1659
+ optimization_goals?: OptimizationGoal[];
1660
+ /**
1661
+ * Flight start date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's start_time. Sellers SHOULD always include the resolved value in responses, even when inherited.
1662
+ * @format date-time
1663
+ */
1664
+ start_time?: string;
1665
+ /**
1666
+ * Flight end date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's end_time. Sellers SHOULD always include the resolved value in responses, even when inherited.
1667
+ * @format date-time
1668
+ */
1669
+ end_time?: string;
1670
+ /**
1671
+ * Whether this package is paused by the buyer. Paused packages do not deliver impressions. Defaults to false.
1672
+ */
1673
+ paused?: boolean;
1674
+ /**
1675
+ * Whether this package has been canceled. Canceled packages stop delivery and cannot be reactivated. Defaults to false.
1676
+ */
1677
+ canceled?: boolean;
1678
+ /**
1679
+ * Cancellation metadata. Present only when canceled is true.
1680
+ */
1681
+ cancellation?: {
1682
+ /**
1683
+ * ISO 8601 timestamp when this package was canceled.
1684
+ * @format date-time
1685
+ */
1686
+ canceled_at: string;
1687
+ canceled_by: CanceledBy;
1688
+ /**
1689
+ * Reason the package was canceled.
1690
+ * @maxLength 500
1691
+ */
1692
+ reason?: string;
1693
+ /**
1694
+ * ISO 8601 timestamp when the seller acknowledged the cancellation. Confirms inventory has been released and billing stopped. Absent until the seller processes the cancellation.
1695
+ * @format date-time
1696
+ */
1697
+ acknowledged_at?: string;
1698
+ };
1699
+ /**
1700
+ * Agency estimate or authorization number for this package. Echoed from the buyer's request. When present on the package, takes precedence over the media buy-level estimate number.
1701
+ * @maxLength 100
1702
+ */
1703
+ agency_estimate_number?: string;
1704
+ /**
1705
+ * ISO 8601 timestamp for creative upload or change deadline for this package. After this deadline, creative changes are rejected. When absent, the media buy's creative_deadline applies.
1706
+ * @format date-time
1707
+ */
1708
+ creative_deadline?: string;
1709
+ context?: ContextObject;
1710
+ ext?: ExtensionObject;
1711
+ }
1712
+
1713
+ /**
1714
+ * Package configuration for media buy creation
1715
+ */
1716
+ export interface PackageRequest {
1717
+ /**
1718
+ * 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.
1719
+ */
1720
+ adcp_version?: string;
1721
+ /**
1722
+ * 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.
1723
+ */
1724
+ adcp_major_version?: number;
1725
+ /**
1726
+ * Product ID for this package
1727
+ */
1728
+ product_id: string;
1729
+ /**
1730
+ * v1 path. Array of format IDs that will be used for this package - must be supported by the product. If omitted (and `capability_ids` is also omitted), defaults to all formats supported by the product.
1731
+ */
1732
+ format_ids?: FormatReferenceStructuredObject[];
1733
+ /**
1734
+ * v2 path. Array of `capability_id` values, each referencing one of the product's `format_options[i].capability_id` entries. Lets a buyer reading the V2 mental model (`Product.format_options[]`) author a `create_media_buy` call without translating back through `v1_format_ref[]` to construct `format_ids[]`. Symmetric with the V2 path exposed on `creative-manifest` (which carries a single `capability_id`) — a package may activate multiple `format_options` entries, so the package-side shape is an array.
1735
+ *
1736
+ * **Resolution rules (normative).**
1737
+ * - **Both `capability_ids` and `format_ids` present.** `capability_ids` wins; the seller routes by `capability_ids` and MUST NOT validate `format_ids` for consistency with the resolved declarations. The `format_ids` value is a v1-compat hint for intermediaries on the wire path; the resolving seller ignores it.
1738
+ * - **`capability_ids` only.** Seller looks up each entry against the product's `format_options[]` and uses the matching declaration (and that declaration's `v1_format_ref[]` when projecting to v1-wire surfaces). This is the V2-native authoring path.
1739
+ * - **`format_ids` only.** Existing v1 behavior; unchanged.
1740
+ * - **Neither.** Default — all formats supported by the product are active.
1741
+ *
1742
+ * **Failure modes (normative).** Sellers MUST reject with `UNSUPPORTED_FEATURE` (with `field` pointing at the failing package and entry, e.g. `packages[0].capability_ids[1]`) when:
1743
+ * - Any entry references a `capability_id` not present in the target product's `format_options[]`, OR
1744
+ * - The target product carries `format_ids` but no `format_options[]` (v1-only product — there is no closed set to resolve against), OR
1745
+ * - The target product carries `format_options[]` but none of the entries publish a `capability_id` (the V2 path is unauthorable against that product). Sellers SHOULD set `error.details.reason` to `capability_ids_not_published` in this case so buyers can distinguish it from an outright mismatch and fall back to `format_ids[]`.
1746
+ *
1747
+ * **Seller obligation.** For buyers to use the V2 path against a product, the seller MUST publish a `capability_id` on each `format_options[]` entry it expects buyers to select (the field is currently optional on `product-format-declaration.json` and only structurally required when multiple entries share a `format_kind`). Sellers SHOULD assign a stable `capability_id` to every entry to keep the V2 authoring path usable.
1748
+ *
1749
+ * **Dual emission.** V2-native buyer SDKs targeting a heterogeneous seller population (mix of v1- and v2-capable sellers) SHOULD emit `format_ids` alongside `capability_ids` so v1-only sellers — which ignore the unknown `capability_ids` field per `additionalProperties: true` — still receive an explicit format set rather than silently defaulting to all formats supported by the product.
1750
+ *
1751
+ * Backward-compatible: additive optional field. v1-only sellers ignore it.
1752
+ */
1753
+ capability_ids?: string[];
1754
+ /**
1755
+ * Budget allocation for this package in the media buy's currency
1756
+ * @minimum 0
1757
+ */
1758
+ budget: number;
1759
+ pacing?: Pacing;
1760
+ /**
1761
+ * ID of the selected pricing option from the product's pricing_options array
1762
+ */
1763
+ pricing_option_id: string;
1764
+ /**
1765
+ * Bid price for auction-based pricing options. This is the exact bid/price to honor unless selected pricing_option has max_bid=true, in which case bid_price is the buyer's maximum willingness to pay (ceiling).
1766
+ * @minimum 0
1767
+ */
1768
+ bid_price?: number;
1769
+ /**
1770
+ * Impression goal for this package
1771
+ * @minimum 0
1772
+ */
1773
+ impressions?: number;
1774
+ /**
1775
+ * Flight start date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's start_time. Must fall within the media buy's date range.
1776
+ * @format date-time
1777
+ */
1778
+ start_time?: string;
1779
+ /**
1780
+ * Flight end date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's end_time. Must fall within the media buy's date range.
1781
+ * @format date-time
1782
+ */
1783
+ end_time?: string;
1784
+ /**
1785
+ * Whether this package should be created in a paused state. Paused packages do not deliver impressions. Defaults to false.
1786
+ */
1787
+ paused?: boolean;
1788
+ /**
1789
+ * Catalogs this package promotes. Each catalog MUST have a distinct type (e.g., one product catalog, one store catalog). This constraint is enforced at the application level — sellers MUST reject requests containing multiple catalogs of the same type with a validation_error. Makes the package catalog-driven: one budget envelope, platform optimizes across items.
1790
+ */
1791
+ catalogs?: Catalog[];
1792
+ /**
1793
+ * Optimization targets for this package. The seller optimizes delivery toward these goals in priority order. Common pattern: event goals (purchase, install) as primary targets at priority 1; metric goals (clicks, views) as secondary proxy signals at priority 2+.
1794
+ */
1795
+ optimization_goals?: OptimizationGoal[];
1796
+ targeting_overlay?: TargetingOverlay;
1797
+ measurement_terms?: MeasurementTerms;
1798
+ /**
1799
+ * Buyer's proposed performance standards for this package. Overrides product defaults. Seller accepts, rejects with TERMS_REJECTED, or adjusts. When absent, product's performance_standards apply.
1800
+ */
1801
+ performance_standards?: PerformanceStandard[];
1802
+ /**
1803
+ * Buyer's proposed reporting contract for this package — the metrics the buyer wants the seller to commit to populating in delivery reports. Same negotiation pattern as `measurement_terms` and `performance_standards`: seller accepts (echoes on confirmed package with `committed_at` stamped), rejects with `TERMS_REJECTED` (with explanation of which entries were unworkable), or normalizes (echoes a different but compatible list — buyer can accept by retrying with the normalized terms). When absent, the seller decides what to commit based on the product's `available_metrics` and the buyer's `required_metrics` filter on `get_products`. Each entry uses an explicit `scope` discriminator (`standard` or `vendor`) and identifies the metric — request-side entries do NOT carry `committed_at`; that timestamp is stamped by the seller on accept. Constraints on what the buyer MAY propose: each `scope: standard` entry's `metric_id` MUST be in the product's `available_metrics`, and each `scope: vendor` entry's `(vendor, metric_id)` MUST appear in the product's `vendor_metrics` — sellers SHOULD reject with `TERMS_REJECTED` and reference the offending entry when the proposal exceeds product capability.
1804
+ */
1805
+ committed_metrics?: ({
1806
+ /**
1807
+ * Standard metric from the closed `available-metric.json` enum.
1808
+ */
1809
+ scope: 'standard';
1810
+ metric_id: AvailableMetric;
1811
+ /**
1812
+ * Disambiguator — same shape as on the response-side `committed_metrics`. Required when the buyer wants to pin a specific measurement path: `viewability_standard` for MRC vs GroupM viewability; `completion_source` for seller- vs vendor-attested `completion_rate`; `attribution_methodology` for how attribution was computed (deterministic_purchase, probabilistic, panel_based, modeled); `attribution_window` for the time window over which outcomes are attributed. See response-side description for full semantics.
1813
+ */
1814
+ qualifier?: {
1815
+ viewability_standard?: ViewabilityStandard;
1816
+ completion_source?: CompletionSource;
1817
+ attribution_methodology?: AttributionMethodology;
1818
+ attribution_window?: Duration;
1819
+ lift_dimension?: LiftDimension;
1820
+ };
1821
+ } | {
1822
+ /**
1823
+ * Vendor-defined metric, identified by the tuple `(vendor, metric_id)`.
1824
+ */
1825
+ scope: 'vendor';
1826
+ vendor: BrandReference;
1827
+ metric_id: VendorMetricID;
1828
+ })[];
1829
+ /**
1830
+ * Assign existing library creatives to this package with optional weights and placement targeting
1831
+ */
1832
+ creative_assignments?: CreativeAssignment[];
1833
+ /**
1834
+ * Upload new creative assets and assign to this package (creatives will be added to library). Use creative_assignments instead for existing library creatives.
1835
+ */
1836
+ creatives?: CreativeAsset[];
1837
+ /**
1838
+ * Agency estimate or authorization number for this package. Overrides the media buy-level estimate number when different packages correspond to different agency estimates (e.g., different stations or flights within the same buy).
1839
+ * @maxLength 100
1840
+ */
1841
+ agency_estimate_number?: string;
1842
+ context?: ContextObject;
1843
+ ext?: ExtensionObject;
1844
+ }
1845
+
1846
+ /**
1847
+ * Package update configuration for update_media_buy. Identifies package by package_id and specifies fields to modify. Fields not present are left unchanged. Fully-immutable fields (product_id, format_ids, pricing_option_id) cannot appear in update payloads — schema-enforced via the `not` constraint at the root of this object. The reporting contract field `committed_metrics` is append-only (sellers MUST accept new entries on update but reject attempts to modify or remove existing entries with validation_error per its own description).
1848
+ */
1849
+ export interface PackageUpdate {
1850
+ /**
1851
+ * Seller's ID of package to update
1852
+ */
1853
+ package_id: string;
1854
+ /**
1855
+ * Updated budget allocation for this package in the currency specified by the pricing option
1856
+ * @minimum 0
1857
+ */
1858
+ budget?: number;
1859
+ pacing?: Pacing;
1860
+ /**
1861
+ * Updated bid price for auction-based pricing options. This is the exact bid/price to honor unless selected pricing_option has max_bid=true, in which case bid_price is the buyer's maximum willingness to pay (ceiling).
1862
+ * @minimum 0
1863
+ */
1864
+ bid_price?: number;
1865
+ /**
1866
+ * Updated impression goal for this package
1867
+ * @minimum 0
1868
+ */
1869
+ impressions?: number;
1870
+ /**
1871
+ * Updated flight start date/time for this package in ISO 8601 format. Must fall within the media buy's date range.
1872
+ * @format date-time
1873
+ */
1874
+ start_time?: string;
1875
+ /**
1876
+ * Updated flight end date/time for this package in ISO 8601 format. Must fall within the media buy's date range.
1877
+ * @format date-time
1878
+ */
1879
+ end_time?: string;
1880
+ /**
1881
+ * Pause/resume specific package (true = paused, false = active)
1882
+ */
1883
+ paused?: boolean;
1884
+ /**
1885
+ * Cancel this specific package. Cancellation is irreversible — canceled packages stop delivery and cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE.
1886
+ */
1887
+ canceled?: true;
1888
+ /**
1889
+ * Reason for canceling this package.
1890
+ * @maxLength 500
1891
+ */
1892
+ cancellation_reason?: string;
1893
+ /**
1894
+ * Replace the catalogs this package promotes. Uses replacement semantics — the provided array replaces the current list. Omit to leave catalogs unchanged.
1895
+ */
1896
+ catalogs?: Catalog[];
1897
+ /**
1898
+ * Replace all optimization goals for this package. Uses replacement semantics — omit to leave goals unchanged.
1899
+ */
1900
+ optimization_goals?: OptimizationGoal[];
1901
+ targeting_overlay?: TargetingOverlay;
1902
+ /**
1903
+ * Keyword targets to add or update on this package. Upserts by (keyword, match_type) identity: if the pair already exists, its bid_price is updated; if not, a new keyword target is added. Use targeting_overlay.keyword_targets in create_media_buy to set the initial list.
1904
+ */
1905
+ keyword_targets_add?: {
1906
+ /**
1907
+ * The keyword to target
1908
+ * @minLength 1
1909
+ */
1910
+ keyword: string;
1911
+ match_type: MatchType;
1912
+ /**
1913
+ * Per-keyword bid price. Inherits currency and max_bid interpretation from the package's pricing option.
1914
+ * @minimum 0
1915
+ */
1916
+ bid_price?: number;
1917
+ }[];
1918
+ /**
1919
+ * Keyword targets to remove from this package. Removes matching (keyword, match_type) pairs. If a specified pair is not present, sellers SHOULD treat it as a no-op for that entry.
1920
+ */
1921
+ keyword_targets_remove?: {
1922
+ /**
1923
+ * The keyword to stop targeting
1924
+ * @minLength 1
1925
+ */
1926
+ keyword: string;
1927
+ match_type: MatchType;
1928
+ }[];
1929
+ /**
1930
+ * Negative keywords to add to this package. Appends to the existing negative keyword list — does not replace it. If a keyword+match_type pair already exists, sellers SHOULD treat it as a no-op for that entry. Use targeting_overlay.negative_keywords in create_media_buy to set the initial list.
1931
+ */
1932
+ negative_keywords_add?: {
1933
+ /**
1934
+ * The keyword to exclude
1935
+ * @minLength 1
1936
+ */
1937
+ keyword: string;
1938
+ match_type: MatchType;
1939
+ }[];
1940
+ /**
1941
+ * Negative keywords to remove from this package. Removes matching keyword+match_type pairs from the existing list. If a specified pair is not present, sellers SHOULD treat it as a no-op for that entry.
1942
+ */
1943
+ negative_keywords_remove?: {
1944
+ /**
1945
+ * The keyword to stop excluding
1946
+ * @minLength 1
1947
+ */
1948
+ keyword: string;
1949
+ match_type: MatchType;
1950
+ }[];
1951
+ /**
1952
+ * Replace creative assignments for this package with optional weights and placement targeting. Uses replacement semantics - omit to leave assignments unchanged.
1953
+ */
1954
+ creative_assignments?: CreativeAssignment[];
1955
+ /**
1956
+ * Upload new creative assets and assign to this package (creatives will be added to library). Use creative_assignments instead for existing library creatives.
1957
+ */
1958
+ creatives?: CreativeAsset[];
1959
+ context?: ContextObject;
1960
+ ext?: ExtensionObject;
1961
+ }
1962
+
1963
+ /**
1964
+ * A rate threshold for a performance metric, measured by a specified vendor. The threshold is a floor or ceiling depending on the metric: viewability, completion_rate, brand_safety, and attention_score are floors (must exceed); ivt is a ceiling (must not exceed).
1965
+ */
1966
+ export interface PerformanceStandard {
1967
+ metric: PerformanceStandardMetric;
1968
+ /**
1969
+ * Rate threshold as a decimal (e.g., 0.70 for 70%). Whether this is a floor or ceiling depends on the metric: for viewability, completion_rate, brand_safety, attention_score the actual rate must be >= threshold; for ivt the actual rate must be <= threshold.
1970
+ * @minimum 0
1971
+ * @maximum 1
1972
+ */
1973
+ threshold: number;
1974
+ standard?: ViewabilityStandard;
1975
+ vendor: BrandReference;
1976
+ }
1977
+
1978
+ /**
1979
+ * The performance metric this standard applies to.
1980
+ */
1981
+ export type PerformanceStandardMetric = 'viewability' | 'ivt' | 'completion_rate' | 'brand_safety' | 'attention_score';
1982
+
1983
+ /**
1984
+ * 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.
1985
+ *
1986
+ * **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.
1987
+ *
1988
+ * - **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`).
1989
+ * - **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.
1990
+ * - **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.
1991
+ * - **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.
1992
+ * - **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).
1993
+ * - **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).
1994
+ * - **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.
1995
+ * - **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.
1996
+ * - **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.
1997
+ * - **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.
1998
+ * - **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.
1999
+ */
2000
+ export interface PlatformExtensionReference {
2001
+ /**
2002
+ * 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.
2003
+ * @pattern ^https:\/\/
2004
+ */
2005
+ uri: string;
2006
+ /**
2007
+ * 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.
2008
+ * @pattern ^sha256:[a-f0-9]{64}$
2009
+ */
2010
+ digest: string;
2011
+ }
2012
+
2013
+ /**
2014
+ * Postal code system (e.g., 'us_zip', 'gb_outward')
2015
+ */
2016
+ export type PostalCodeSystem = 'us_zip' | 'us_zip_plus_four' | 'gb_outward' | 'gb_full' | 'ca_fsa' | 'ca_full' | 'de_plz' | 'fr_code_postal' | 'au_postcode' | 'ch_plz' | 'at_plz';
2017
+
2018
+ /**
2019
+ * Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.
2020
+ */
2021
+ export interface PriceBreakdown {
2022
+ /**
2023
+ * Rate card or base price before any adjustments. The starting point from which fixed_price is derived by applying fee and discount adjustments sequentially.
2024
+ */
2025
+ list_price: number;
2026
+ /**
2027
+ * Ordered list of price adjustments. Fee and discount adjustments walk list_price to fixed_price — fees increase the running price, discounts reduce it. Commission and settlement adjustments are disclosed for transparency but do not affect the buyer's committed price.
2028
+ */
2029
+ adjustments: {
2030
+ [k: string]: unknown | undefined;
2031
+ }[];
2032
+ }
2033
+
2034
+ /**
2035
+ * [AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.
2036
+ */
2037
+ export interface PropertyListReference {
2038
+ /**
2039
+ * URL of the agent managing the property list
2040
+ */
2041
+ agent_url: string;
2042
+ /**
2043
+ * Identifier for the property list within the agent
2044
+ * @minLength 1
2045
+ */
2046
+ list_id: string;
2047
+ /**
2048
+ * JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access.
2049
+ */
2050
+ auth_token?: string;
2051
+ }
2052
+
2053
+ /**
2054
+ * Provenance metadata for this asset, overrides manifest-level provenance
2055
+ */
2056
+ export interface Provenance {
2057
+ digital_source_type?: DigitalSourceType;
2058
+ /**
2059
+ * AI system used to generate or modify this content. Aligns with IPTC 2025.1 AI metadata fields and C2PA claim_generator.
2060
+ */
2061
+ ai_tool?: {
2062
+ /**
2063
+ * Name of the AI tool or model (e.g., 'DALL-E 3', 'Stable Diffusion XL', 'Gemini')
2064
+ */
2065
+ name: string;
2066
+ /**
2067
+ * 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.
2068
+ */
2069
+ version?: string;
2070
+ /**
2071
+ * Organization that provides the AI tool (e.g., 'OpenAI', 'Stability AI', 'Google')
2072
+ */
2073
+ provider?: string;
2074
+ };
2075
+ /**
2076
+ * 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`.
2077
+ */
2078
+ human_oversight?: 'none' | 'prompt_only' | 'selected' | 'edited' | 'directed';
2079
+ /**
2080
+ * Party declaring this provenance. Identifies who attached the provenance claim, enabling receiving parties to assess trust.
2081
+ */
2082
+ declared_by?: {
2083
+ /**
2084
+ * URL of the agent or service that declared this provenance
2085
+ */
2086
+ agent_url?: string;
2087
+ /**
2088
+ * Role of the declaring party in the supply chain
2089
+ */
2090
+ role: 'creator' | 'advertiser' | 'agency' | 'platform' | 'tool';
2091
+ };
2092
+ /**
2093
+ * 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.
2094
+ * @format date-time
2095
+ */
2096
+ declared_at?: string;
2097
+ /**
2098
+ * When this content was created or generated (ISO 8601)
2099
+ * @format date-time
2100
+ */
2101
+ created_time?: string;
2102
+ /**
2103
+ * 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.
2104
+ */
2105
+ c2pa?: {
2106
+ /**
2107
+ * URL to the C2PA manifest store for this content
2108
+ */
2109
+ manifest_url: string;
2110
+ };
2111
+ /**
2112
+ * 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`).
2113
+ */
2114
+ embedded_provenance?: {
2115
+ method: EmbeddedProvenanceMethod;
2116
+ /**
2117
+ * Standard the embedding conforms to, if any (e.g., 'c2pa' for C2PA Section A.7 text manifest embedding)
2118
+ */
2119
+ standard?: string;
2120
+ /**
2121
+ * Organization that performed the embedding (e.g., 'Encypher', 'Digimarc'). Display label and audit context — not a wire identifier.
2122
+ */
2123
+ provider: string;
2124
+ /**
2125
+ * 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).
2126
+ */
2127
+ verify_agent?: {
2128
+ /**
2129
+ * 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.
2130
+ * @pattern ^https:\/\/
2131
+ */
2132
+ agent_url: string;
2133
+ /**
2134
+ * 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.
2135
+ */
2136
+ feature_id?: string;
2137
+ };
2138
+ /**
2139
+ * When the provenance data was embedded (ISO 8601)
2140
+ * @format date-time
2141
+ */
2142
+ embedded_at?: string;
2143
+ }[];
2144
+ /**
2145
+ * 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`).
2146
+ */
2147
+ watermarks?: {
2148
+ media_type: WatermarkMediaType;
2149
+ /**
2150
+ * Organization that applied the watermark (e.g., 'Imatag', 'Steg.AI', 'Encypher'). Display label and audit context — not a wire identifier.
2151
+ */
2152
+ provider: string;
2153
+ /**
2154
+ * 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).
2155
+ */
2156
+ verify_agent?: {
2157
+ /**
2158
+ * 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.
2159
+ * @pattern ^https:\/\/
2160
+ */
2161
+ agent_url: string;
2162
+ /**
2163
+ * 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.
2164
+ */
2165
+ feature_id?: string;
2166
+ };
2167
+ c2pa_action?: C2PAWatermarkAction;
2168
+ /**
2169
+ * When the watermark was applied (ISO 8601)
2170
+ * @format date-time
2171
+ */
2172
+ embedded_at?: string;
2173
+ }[];
2174
+ /**
2175
+ * Regulatory disclosure requirements for this content. Indicates whether AI disclosure is required and under which jurisdictions.
2176
+ */
2177
+ disclosure?: {
2178
+ /**
2179
+ * 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.
2180
+ */
2181
+ required: boolean;
2182
+ /**
2183
+ * Jurisdictions where disclosure obligations apply
2184
+ */
2185
+ jurisdictions?: {
2186
+ /**
2187
+ * ISO 3166-1 alpha-2 country code (e.g., 'US', 'DE', 'CN')
2188
+ */
2189
+ country: string;
2190
+ /**
2191
+ * Sub-national region code (e.g., 'CA' for California, 'BY' for Bavaria)
2192
+ */
2193
+ region?: string;
2194
+ /**
2195
+ * Regulation identifier (e.g., 'eu_ai_act_article_50', 'ca_sb_942', 'cn_deep_synthesis')
2196
+ */
2197
+ regulation: string;
2198
+ /**
2199
+ * Required disclosure label text for this jurisdiction, in the local language
2200
+ */
2201
+ label_text?: string;
2202
+ /**
2203
+ * 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.
2204
+ */
2205
+ render_guidance?: {
2206
+ persistence?: DisclosurePersistence;
2207
+ /**
2208
+ * 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.
2209
+ * @minimum 1
2210
+ */
2211
+ min_duration_ms?: number;
2212
+ /**
2213
+ * Preferred disclosure positions in priority order. The first position a format supports should be used.
2214
+ */
2215
+ positions?: DisclosurePosition[];
2216
+ ext?: ExtensionObject;
2217
+ };
2218
+ }[];
2219
+ };
2220
+ /**
2221
+ * 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.
2222
+ */
2223
+ verification?: {
2224
+ /**
2225
+ * Name of the verification service (e.g., 'DoubleVerify', 'Hive Moderation', 'Reality Defender')
2226
+ */
2227
+ verified_by: string;
2228
+ /**
2229
+ * When the verification was performed (ISO 8601)
2230
+ * @format date-time
2231
+ */
2232
+ verified_time?: string;
2233
+ /**
2234
+ * Verification outcome
2235
+ */
2236
+ result: 'authentic' | 'ai_generated' | 'ai_modified' | 'inconclusive';
2237
+ /**
2238
+ * Confidence score of the verification result (0.0 to 1.0)
2239
+ * @minimum 0
2240
+ * @maximum 1
2241
+ */
2242
+ confidence?: number;
2243
+ /**
2244
+ * URL to the full verification report
2245
+ */
2246
+ details_url?: string;
2247
+ }[];
2248
+ ext?: ExtensionObject;
2249
+ }
2250
+
2251
+ /**
2252
+ * 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.
2253
+ */
2254
+ export interface PushNotificationConfig {
2255
+ /**
2256
+ * 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).
2257
+ */
2258
+ url: string;
2259
+ /**
2260
+ * 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`.
2261
+ * @minLength 1
2262
+ * @maxLength 255
2263
+ * @pattern ^[A-Za-z0-9_.:-]{1,255}$
2264
+ */
2265
+ operation_id?: string;
2266
+ /**
2267
+ * 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.
2268
+ * @minLength 16
2269
+ * @maxLength 4096
2270
+ */
2271
+ token?: string;
2272
+ /**
2273
+ * 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).
2274
+ */
2275
+ authentication?: {
2276
+ /**
2277
+ * 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.
2278
+ */
2279
+ schemes: AuthenticationScheme[];
2280
+ /**
2281
+ * 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.
2282
+ * @minLength 32
2283
+ */
2284
+ credentials: string;
2285
+ };
2286
+ }
2287
+
2288
+ /**
2289
+ * Unit of measurement for reach and audience_size metrics in this forecast. Required for cross-channel forecast comparison.
2290
+ */
2291
+ export type ReachUnit = 'individuals' | 'households' | 'devices' | 'accounts' | 'cookies' | 'custom';
2292
+
2293
+ /**
2294
+ * 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.
2295
+ */
2296
+ export interface ReferenceAsset {
2297
+ /**
2298
+ * URL to the reference asset (image, video, or document)
2299
+ */
2300
+ url: string;
2301
+ /**
2302
+ * 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
2303
+ */
2304
+ role: 'style_reference' | 'product_shot' | 'mood_board' | 'example_creative' | 'logo' | 'strategy_doc' | 'storyboard';
2305
+ /**
2306
+ * Human-readable description of the asset and how it should inform creative generation
2307
+ */
2308
+ description?: string;
2309
+ }
2310
+
2311
+ /**
2312
+ * Optional webhook configuration for automated reporting delivery
2313
+ */
2314
+ export interface ReportingWebhook {
2315
+ /**
2316
+ * Webhook endpoint URL for reporting notifications
2317
+ */
2318
+ url: string;
2319
+ /**
2320
+ * Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.
2321
+ * @minLength 16
2322
+ */
2323
+ token?: string;
2324
+ /**
2325
+ * Legacy authentication configuration for webhook delivery (A2A-compatible). Opts the receiver into Bearer or HMAC-SHA256 signing. Both schemes are deprecated; the preferred signing profile for new integrations is RFC 9421, where the seller signs with a key published at its brand.json agents[] entry and the buyer verifies against the seller's JWKS — no shared secret crosses the wire (see docs/building/implementation/security.mdx#webhook-callbacks). This field is required in AdCP 3.x; the requirement is removed in AdCP 4.0 when the default RFC 9421 path becomes the only path.
2326
+ */
2327
+ authentication: {
2328
+ /**
2329
+ * Array of authentication schemes. ['Bearer'] for simple token auth, ['HMAC-SHA256'] for legacy shared-secret signing. Both are deprecated; new integrations SHOULD use the RFC 9421 webhook signing profile instead.
2330
+ */
2331
+ schemes: AuthenticationScheme[];
2332
+ /**
2333
+ * 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.
2334
+ * @minLength 32
2335
+ */
2336
+ credentials: string;
2337
+ };
2338
+ /**
2339
+ * Frequency for automated reporting delivery. Must be supported by all products in the media buy.
2340
+ */
2341
+ reporting_frequency: 'hourly' | 'daily' | 'monthly';
2342
+ /**
2343
+ * Optional list of metrics to include in webhook notifications. If omitted, all available metrics are included. Must be subset of product's available_metrics.
2344
+ */
2345
+ requested_metrics?: AvailableMetric[];
2346
+ }
2347
+
2348
+ /**
2349
+ * Optional SLA commitment for this action on this product. Absence means no commitment.
2350
+ */
2351
+ export interface SLAWindow {
2352
+ /**
2353
+ * Maximum time from when the buyer issues the action to when the seller acknowledges receipt (mode-appropriate: synchronous response for self_serve, queue ack for requires_approval, proposal task creation for requires_proposal). ISO 8601 duration.
2354
+ * @pattern ^P(?!$)(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$
2355
+ */
2356
+ response_max?: string;
2357
+ /**
2358
+ * Maximum time from buyer issuing the action to the seller completing it (mutation applied, proposal finalized, approval resolved). ISO 8601 duration.
2359
+ * @pattern ^P(?!$)(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$
2360
+ */
2361
+ completion_max?: string;
2362
+ }
2363
+
2364
+ /**
2365
+ * Video scan method. Modern digital delivery requires progressive scan; interlaced is retained for broadcast legacy content.
2366
+ */
2367
+ export type ScanType = 'progressive' | 'interlaced';
2368
+
2369
+ /**
2370
+ * Campaign start timing: 'asap' or ISO 8601 date-time
2371
+ */
2372
+ export type StartTiming = 'asap' | string;
2373
+
2374
+ /**
2375
+ * Optional restriction overlays for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are for functional restrictions: geographic (RCT testing, regulatory compliance, proximity targeting), age verification (alcohol, gambling), device platform (app compatibility), language (localization), and keyword targeting (search/retail media).
2376
+ */
2377
+ export interface TargetingOverlay {
2378
+ /**
2379
+ * Restrict delivery to specific countries. ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE').
2380
+ */
2381
+ geo_countries?: string[];
2382
+ /**
2383
+ * Exclude specific countries from delivery. ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE').
2384
+ */
2385
+ geo_countries_exclude?: string[];
2386
+ /**
2387
+ * Restrict delivery to specific regions/states. ISO 3166-2 subdivision codes (e.g., 'US-CA', 'GB-SCT').
2388
+ */
2389
+ geo_regions?: string[];
2390
+ /**
2391
+ * Exclude specific regions/states from delivery. ISO 3166-2 subdivision codes (e.g., 'US-CA', 'GB-SCT').
2392
+ */
2393
+ geo_regions_exclude?: string[];
2394
+ /**
2395
+ * Restrict delivery to specific metro areas. Each entry specifies the classification system and target values. Seller must declare supported systems in get_adcp_capabilities.
2396
+ */
2397
+ geo_metros?: {
2398
+ system: MetroAreaSystem;
2399
+ /**
2400
+ * Metro codes within the system (e.g., ['501', '602'] for Nielsen DMAs)
2401
+ */
2402
+ values: string[];
2403
+ }[];
2404
+ /**
2405
+ * Exclude specific metro areas from delivery. Each entry specifies the classification system and excluded values. Seller must declare supported systems in get_adcp_capabilities.
2406
+ */
2407
+ geo_metros_exclude?: {
2408
+ system: MetroAreaSystem;
2409
+ /**
2410
+ * Metro codes to exclude within the system (e.g., ['501', '602'] for Nielsen DMAs)
2411
+ */
2412
+ values: string[];
2413
+ }[];
2414
+ /**
2415
+ * Restrict delivery to specific postal areas. Each entry specifies the postal system and target values. Seller must declare supported systems in get_adcp_capabilities.
2416
+ */
2417
+ geo_postal_areas?: {
2418
+ system: PostalCodeSystem;
2419
+ /**
2420
+ * Postal codes within the system (e.g., ['10001', '10002'] for us_zip)
2421
+ */
2422
+ values: string[];
2423
+ }[];
2424
+ /**
2425
+ * Exclude specific postal areas from delivery. Each entry specifies the postal system and excluded values. Seller must declare supported systems in get_adcp_capabilities.
2426
+ */
2427
+ geo_postal_areas_exclude?: {
2428
+ system: PostalCodeSystem;
2429
+ /**
2430
+ * Postal codes to exclude within the system (e.g., ['10001', '10002'] for us_zip)
2431
+ */
2432
+ values: string[];
2433
+ }[];
2434
+ /**
2435
+ * Restrict delivery to specific time windows. Each entry specifies days of week and an hour range.
2436
+ */
2437
+ daypart_targets?: DaypartTarget[];
2438
+ /**
2439
+ * @deprecated
2440
+ * Deprecated: Use TMP provider fields instead. AXE segment ID to include for targeting.
2441
+ */
2442
+ axe_include_segment?: string;
2443
+ /**
2444
+ * @deprecated
2445
+ * Deprecated: Use TMP provider fields instead. AXE segment ID to exclude from targeting.
2446
+ */
2447
+ axe_exclude_segment?: string;
2448
+ /**
2449
+ * Restrict delivery to members of these first-party CRM audiences. Only users present in the uploaded lists are eligible. References audience_id values from sync_audiences on the same seller account — audience IDs are not portable across sellers. Not for lookalike expansion — express that intent in the campaign brief. Seller must declare support in get_adcp_capabilities.
2450
+ */
2451
+ audience_include?: string[];
2452
+ /**
2453
+ * Suppress delivery to members of these first-party CRM audiences. Matched users are excluded regardless of other targeting. References audience_id values from sync_audiences on the same seller account — audience IDs are not portable across sellers. Seller must declare support in get_adcp_capabilities.
2454
+ */
2455
+ audience_exclude?: string[];
2456
+ frequency_cap?: FrequencyCap;
2457
+ property_list?: PropertyListReference;
2458
+ collection_list?: CollectionListReference;
2459
+ collection_list_exclude?: CollectionListReference;
2460
+ /**
2461
+ * Age restriction for compliance. Use for legal requirements (alcohol, gambling), not audience targeting.
2462
+ */
2463
+ age_restriction?: {
2464
+ /**
2465
+ * Minimum age required
2466
+ * @minimum 13
2467
+ * @maximum 99
2468
+ */
2469
+ min: number;
2470
+ /**
2471
+ * Whether verified age (not inferred) is required for compliance
2472
+ */
2473
+ verification_required?: boolean;
2474
+ /**
2475
+ * Accepted verification methods. If omitted, any method the platform supports is acceptable.
2476
+ */
2477
+ accepted_methods?: AgeVerificationMethod[];
2478
+ };
2479
+ /**
2480
+ * Restrict to specific platforms. Use for technical compatibility (app only works on iOS). Values from Sec-CH-UA-Platform standard, extended for CTV.
2481
+ */
2482
+ device_platform?: DevicePlatform[];
2483
+ /**
2484
+ * Restrict to specific device form factors. Use for campaigns targeting hardware categories rather than operating systems (e.g., mobile-only promotions, CTV campaigns).
2485
+ */
2486
+ device_type?: DeviceType[];
2487
+ /**
2488
+ * Exclude specific device form factors from delivery (e.g., exclude CTV for app-install campaigns).
2489
+ */
2490
+ device_type_exclude?: DeviceType[];
2491
+ /**
2492
+ * Target users within store catchment areas from a synced store catalog. Each entry references a store-type catalog and optionally narrows to specific stores or catchment zones.
2493
+ */
2494
+ store_catchments?: {
2495
+ /**
2496
+ * Synced store-type catalog ID from sync_catalogs.
2497
+ */
2498
+ catalog_id: string;
2499
+ /**
2500
+ * Filter to specific stores within the catalog. Omit to target all stores.
2501
+ */
2502
+ store_ids?: string[];
2503
+ /**
2504
+ * Catchment zone IDs to target (e.g., 'walk', 'drive'). Omit to target all catchment zones.
2505
+ */
2506
+ catchment_ids?: string[];
2507
+ }[];
2508
+ /**
2509
+ * Target users within travel time, distance, or a custom boundary around arbitrary geographic points. Multiple entries use OR semantics — a user within range of any listed point is eligible. For campaigns targeting 10+ locations, consider using store_catchments with a location catalog instead. Seller must declare support in get_adcp_capabilities.
2510
+ */
2511
+ geo_proximity?: {
2512
+ [k: string]: unknown | undefined;
2513
+ }[];
2514
+ /**
2515
+ * Restrict to users with specific language preferences. ISO 639-1 codes (e.g., 'en', 'es', 'fr').
2516
+ */
2517
+ language?: string[];
2518
+ /**
2519
+ * Keyword targeting for search and retail media platforms. Restricts delivery to queries matching the specified keywords. Each keyword is identified by the tuple (keyword, match_type) — the same keyword string with different match types are distinct targets. Sellers SHOULD reject duplicate (keyword, match_type) pairs within a single request. Seller must declare support in get_adcp_capabilities.
2520
+ */
2521
+ keyword_targets?: {
2522
+ /**
2523
+ * The keyword to target
2524
+ * @minLength 1
2525
+ */
2526
+ keyword: string;
2527
+ match_type: MatchType;
2528
+ /**
2529
+ * Per-keyword bid price, denominated in the same currency as the package's pricing option. Overrides the package-level bid_price for this keyword. Inherits the max_bid interpretation from the pricing option: when max_bid is true, this is the keyword's bid ceiling; when false, this is the exact bid. If omitted, the package bid_price applies.
2530
+ * @minimum 0
2531
+ */
2532
+ bid_price?: number;
2533
+ }[];
2534
+ /**
2535
+ * Keywords to exclude from delivery. Queries matching these keywords will not trigger the ad. Each negative keyword is identified by the tuple (keyword, match_type). Seller must declare support in get_adcp_capabilities.
2536
+ */
2537
+ negative_keywords?: {
2538
+ /**
2539
+ * The keyword to exclude
2540
+ * @minLength 1
2541
+ */
2542
+ keyword: string;
2543
+ match_type: MatchType;
2544
+ }[];
2545
+ }
2546
+
2547
+ /**
2548
+ * 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.
2549
+ */
2550
+ export type TaskStatus = 'submitted' | 'working' | 'input-required' | 'completed' | 'canceled' | 'failed' | 'rejected' | 'auth-required' | 'unknown';
2551
+
2552
+ /**
2553
+ * Text content asset
2554
+ */
2555
+ export interface TextAsset {
2556
+ /**
2557
+ * Discriminator identifying this as a text asset. See /schemas/creative/asset-types for the registry.
2558
+ */
2559
+ asset_type: 'text';
2560
+ /**
2561
+ * Text content
2562
+ */
2563
+ content: string;
2564
+ /**
2565
+ * Language code (e.g., 'en', 'es', 'fr')
2566
+ */
2567
+ language?: string;
2568
+ provenance?: Provenance;
2569
+ }
2570
+
2571
+ /**
2572
+ * 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.
2573
+ */
2574
+ export interface URLAsset {
2575
+ /**
2576
+ * Discriminator identifying this as a URL asset. See /schemas/creative/asset-types for the registry.
2577
+ */
2578
+ asset_type: 'url';
2579
+ /**
2580
+ * 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.
2581
+ */
2582
+ url: string;
2583
+ url_type?: URLAssetType;
2584
+ /**
2585
+ * Description of what this URL points to
2586
+ */
2587
+ description?: string;
2588
+ provenance?: Provenance;
2589
+ }
2590
+
2591
+ /**
2592
+ * 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.
2593
+ */
2594
+ export type URLAssetType = 'clickthrough' | 'tracker_pixel' | 'tracker_script';
2595
+
2596
+ /**
2597
+ * 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.
2598
+ */
2599
+ 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';
2600
+
2601
+ /**
2602
+ * 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.
2603
+ */
2604
+ export type UpdateFrequency = 'realtime' | 'hourly' | 'daily' | 'weekly';
2605
+
2606
+ /**
2607
+ * Creative references a named format via the structured `format_id` object. The v1 path; remains supported through 4.x.
2608
+ */
2609
+ export interface V1CreativeNamedFormatReference {
2610
+ /**
2611
+ * Unique identifier for the creative. Stable across v1 and v2 paths — a creative registered against v1 `format_id` retains the same `creative_id` when later viewed via v2 flatten.
2612
+ */
2613
+ creative_id: string;
2614
+ /**
2615
+ * Human-readable creative name
2616
+ */
2617
+ name: string;
2618
+ format_id: FormatReferenceStructuredObject;
2619
+ /**
2620
+ * v2 path, optional. Stable identifier matching one of the seller's product `format_options[i].capability_id` values. REQUIRED only when the target product has multiple `format_options` entries sharing the same `format_kind`.
2621
+ */
2622
+ capability_id?: string;
2623
+ /**
2624
+ * Assets required by the format, keyed by asset_id. Each slot value is either a single asset object or an array of asset objects (for slots with `min`/`max > 1` like carousel `cards` or responsive_creative `headlines`). Each asset value carries an `asset_type` discriminator that selects the matching asset schema.
2625
+ */
2626
+ assets: {
2627
+ /**
2628
+ * This interface was referenced by `undefined`'s JSON-Schema definition
2629
+ * via the `patternProperty` "^[a-z0-9_]+$".
2630
+ */
2631
+ [k: string]: AssetVariant | AssetVariant[];
2632
+ };
2633
+ /**
2634
+ * Preview contexts for generative formats - defines what scenarios to generate previews for
2635
+ */
2636
+ inputs?: {
2637
+ /**
2638
+ * Human-readable name for this preview variant
2639
+ */
2640
+ name: string;
2641
+ /**
2642
+ * Macro values to apply for this preview
2643
+ */
2644
+ macros?: {
2645
+ [k: string]: string | undefined;
2646
+ };
2647
+ /**
2648
+ * Natural language description of the context for AI-generated content
2649
+ */
2650
+ context_description?: string;
2651
+ }[];
2652
+ /**
2653
+ * User-defined tags for organization and searchability
2654
+ */
2655
+ tags?: string[];
2656
+ status?: CreativeStatus;
2657
+ /**
2658
+ * Optional delivery weight for creative rotation when uploading via create_media_buy or update_media_buy (0-100). If omitted, platform determines rotation. Only used during upload to media buy - not stored in creative library.
2659
+ * @minimum 0
2660
+ * @maximum 100
2661
+ */
2662
+ weight?: number;
2663
+ /**
2664
+ * Optional array of placement IDs where this creative should run when uploading via create_media_buy or update_media_buy. References placement_id values from the product's placements array. If omitted, creative runs on all placements. Only used during upload to media buy - not stored in creative library.
2665
+ */
2666
+ placement_ids?: string[];
2667
+ /**
2668
+ * Industry-standard identifiers for this creative (e.g., Ad-ID, ISCI, Clearcast clock number). In broadcast buying, these identifiers tie the creative to rotation instructions and traffic systems. A creative may have multiple identifiers when different systems reference the same asset.
2669
+ */
2670
+ industry_identifiers?: IndustryIdentifier[];
2671
+ provenance?: Provenance;
2672
+ }
2673
+
2674
+ /**
2675
+ * Creative declares which canonical format it targets via `format_kind` (e.g., `image`). The v2 path introduced by RFC #3305.
2676
+ */
2677
+ export interface V2CreativeCanonicalFormatKind {
2678
+ /**
2679
+ * Unique identifier for the creative. Stable across v1 and v2 paths — a creative registered against v1 `format_id` retains the same `creative_id` when later viewed via v2 flatten.
2680
+ */
2681
+ creative_id: string;
2682
+ /**
2683
+ * Human-readable creative name
2684
+ */
2685
+ name: string;
2686
+ format_kind: CanonicalFormatKind;
2687
+ /**
2688
+ * v2 path, optional. Stable identifier matching one of the seller's product `format_options[i].capability_id` values. REQUIRED only when the target product has multiple `format_options` entries sharing the same `format_kind`.
2689
+ */
2690
+ capability_id?: string;
2691
+ /**
2692
+ * Assets required by the format, keyed by asset_id. Each slot value is either a single asset object or an array of asset objects (for slots with `min`/`max > 1` like carousel `cards` or responsive_creative `headlines`). Each asset value carries an `asset_type` discriminator that selects the matching asset schema.
2693
+ */
2694
+ assets: {
2695
+ /**
2696
+ * This interface was referenced by `undefined`'s JSON-Schema definition
2697
+ * via the `patternProperty` "^[a-z0-9_]+$".
2698
+ */
2699
+ [k: string]: AssetVariant | AssetVariant[];
2700
+ };
2701
+ /**
2702
+ * Preview contexts for generative formats - defines what scenarios to generate previews for
2703
+ */
2704
+ inputs?: {
2705
+ /**
2706
+ * Human-readable name for this preview variant
2707
+ */
2708
+ name: string;
2709
+ /**
2710
+ * Macro values to apply for this preview
2711
+ */
2712
+ macros?: {
2713
+ [k: string]: string | undefined;
2714
+ };
2715
+ /**
2716
+ * Natural language description of the context for AI-generated content
2717
+ */
2718
+ context_description?: string;
2719
+ }[];
2720
+ /**
2721
+ * User-defined tags for organization and searchability
2722
+ */
2723
+ tags?: string[];
2724
+ status?: CreativeStatus;
2725
+ /**
2726
+ * Optional delivery weight for creative rotation when uploading via create_media_buy or update_media_buy (0-100). If omitted, platform determines rotation. Only used during upload to media buy - not stored in creative library.
2727
+ * @minimum 0
2728
+ * @maximum 100
2729
+ */
2730
+ weight?: number;
2731
+ /**
2732
+ * Optional array of placement IDs where this creative should run when uploading via create_media_buy or update_media_buy. References placement_id values from the product's placements array. If omitted, creative runs on all placements. Only used during upload to media buy - not stored in creative library.
2733
+ */
2734
+ placement_ids?: string[];
2735
+ /**
2736
+ * Industry-standard identifiers for this creative (e.g., Ad-ID, ISCI, Clearcast clock number). In broadcast buying, these identifiers tie the creative to rotation instructions and traffic systems. A creative may have multiple identifiers when different systems reference the same asset.
2737
+ */
2738
+ industry_identifiers?: IndustryIdentifier[];
2739
+ provenance?: Provenance;
2740
+ }
2741
+
2742
+ /**
2743
+ * VAST (Video Ad Serving Template) tag for third-party video ad serving
2744
+ */
2745
+ export type VASTAsset = {
2746
+ /**
2747
+ * Discriminator identifying this as a VAST asset. See /schemas/creative/asset-types for the registry.
2748
+ */
2749
+ asset_type: 'vast';
2750
+ vast_version?: VASTVersion;
2751
+ /**
2752
+ * Whether VPAID (Video Player-Ad Interface Definition) is supported
2753
+ */
2754
+ vpaid_enabled?: boolean;
2755
+ /**
2756
+ * Expected video duration in milliseconds (if known)
2757
+ * @minimum 0
2758
+ */
2759
+ duration_ms?: number;
2760
+ /**
2761
+ * Tracking events supported by this VAST tag
2762
+ */
2763
+ tracking_events?: VASTTrackingEvent[];
2764
+ /**
2765
+ * URL to captions file (WebVTT, SRT, etc.)
2766
+ */
2767
+ captions_url?: string;
2768
+ /**
2769
+ * URL to audio description track for visually impaired users
2770
+ */
2771
+ audio_description_url?: string;
2772
+ provenance?: Provenance;
2773
+ } & ({
2774
+ /**
2775
+ * Discriminator indicating VAST is delivered via URL endpoint
2776
+ */
2777
+ delivery_type: 'url';
2778
+ /**
2779
+ * URL endpoint that returns VAST XML
2780
+ */
2781
+ url: string;
2782
+ } | {
2783
+ /**
2784
+ * Discriminator indicating VAST is delivered as inline XML content
2785
+ */
2786
+ delivery_type: 'inline';
2787
+ /**
2788
+ * Inline VAST XML content
2789
+ */
2790
+ content: string;
2791
+ });
2792
+
2793
+ /**
2794
+ * 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.
2795
+ */
2796
+ 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';
2797
+
2798
+ /**
2799
+ * VAST specification version
2800
+ */
2801
+ export type VASTVersion = '2.0' | '3.0' | '4.0' | '4.1' | '4.2';
2802
+
2803
+ /**
2804
+ * Identifier for the metric within the vendor's vocabulary (e.g., `attention_units`, `gco2e_per_impression`, `demographic_reach`).
2805
+ */
2806
+ export type VendorMetricID = string;
2807
+
2808
+ /**
2809
+ * Video asset with URL and technical specifications including audio track properties
2810
+ */
2811
+ export interface VideoAsset {
2812
+ /**
2813
+ * Discriminator identifying this as a video asset. See /schemas/creative/asset-types for the registry.
2814
+ */
2815
+ asset_type: 'video';
2816
+ /**
2817
+ * URL to the video asset
2818
+ */
2819
+ url: string;
2820
+ /**
2821
+ * Width in pixels
2822
+ * @minimum 1
2823
+ */
2824
+ width: number;
2825
+ /**
2826
+ * Height in pixels
2827
+ * @minimum 1
2828
+ */
2829
+ height: number;
2830
+ /**
2831
+ * Video duration in milliseconds
2832
+ * @minimum 1
2833
+ */
2834
+ duration_ms?: number;
2835
+ /**
2836
+ * File size in bytes
2837
+ * @minimum 1
2838
+ */
2839
+ file_size_bytes?: number;
2840
+ /**
2841
+ * Video container format (mp4, webm, mov, etc.)
2842
+ */
2843
+ container_format?: string;
2844
+ /**
2845
+ * Video codec used (h264, h265, vp9, av1, prores, etc.)
2846
+ */
2847
+ video_codec?: string;
2848
+ /**
2849
+ * Video stream bitrate in kilobits per second
2850
+ * @minimum 1
2851
+ */
2852
+ video_bitrate_kbps?: number;
2853
+ /**
2854
+ * Frame rate as string to preserve precision (e.g., '23.976', '29.97', '30')
2855
+ */
2856
+ frame_rate?: string;
2857
+ frame_rate_type?: FrameRateType;
2858
+ scan_type?: ScanType;
2859
+ /**
2860
+ * Color space of the video
2861
+ */
2862
+ color_space?: 'rec709' | 'rec2020' | 'rec2100' | 'srgb' | 'dci_p3';
2863
+ /**
2864
+ * HDR format if applicable, or 'sdr' for standard dynamic range
2865
+ */
2866
+ hdr_format?: 'sdr' | 'hdr10' | 'hdr10_plus' | 'hlg' | 'dolby_vision';
2867
+ /**
2868
+ * Chroma subsampling format
2869
+ */
2870
+ chroma_subsampling?: '4:2:0' | '4:2:2' | '4:4:4';
2871
+ /**
2872
+ * Video bit depth
2873
+ */
2874
+ video_bit_depth?: 8 | 10 | 12;
2875
+ /**
2876
+ * GOP/keyframe interval in seconds
2877
+ */
2878
+ gop_interval_seconds?: number;
2879
+ gop_type?: GOPType;
2880
+ moov_atom_position?: MoovAtomPosition;
2881
+ /**
2882
+ * Whether the video contains an audio track
2883
+ */
2884
+ has_audio?: boolean;
2885
+ /**
2886
+ * Audio codec used (aac, aac_lc, he_aac, pcm, mp3, ac3, eac3, etc.)
2887
+ */
2888
+ audio_codec?: string;
2889
+ /**
2890
+ * Audio sampling rate in Hz (e.g., 44100, 48000)
2891
+ */
2892
+ audio_sampling_rate_hz?: number;
2893
+ audio_channels?: AudioChannelLayout;
2894
+ /**
2895
+ * Audio bit depth
2896
+ */
2897
+ audio_bit_depth?: 16 | 24 | 32;
2898
+ /**
2899
+ * Audio bitrate in kilobits per second
2900
+ * @minimum 1
2901
+ */
2902
+ audio_bitrate_kbps?: number;
2903
+ /**
2904
+ * Integrated loudness in LUFS
2905
+ */
2906
+ audio_loudness_lufs?: number;
2907
+ /**
2908
+ * True peak level in dBFS
2909
+ */
2910
+ audio_true_peak_dbfs?: number;
2911
+ /**
2912
+ * URL to captions file (WebVTT, SRT, etc.)
2913
+ */
2914
+ captions_url?: string;
2915
+ /**
2916
+ * URL to text transcript of the video content
2917
+ */
2918
+ transcript_url?: string;
2919
+ /**
2920
+ * URL to audio description track for visually impaired users
2921
+ */
2922
+ audio_description_url?: string;
2923
+ provenance?: Provenance;
2924
+ }
2925
+
2926
+ /**
2927
+ * Measurement standard. Required when metric is 'viewability' (MRC and GroupM define materially different thresholds). Omit for other metrics.
2928
+ */
2929
+ export type ViewabilityStandard = 'mrc' | 'groupm';
2930
+
2931
+ /**
2932
+ * Media category of the watermarked content
2933
+ */
2934
+ export type WatermarkMediaType = 'audio' | 'image' | 'video' | 'text';
2935
+
2936
+ /**
2937
+ * Webhook for server-side dynamic content rendering (DCO)
2938
+ */
2939
+ export interface WebhookAsset {
2940
+ /**
2941
+ * Discriminator identifying this as a webhook asset. See /schemas/creative/asset-types for the registry.
2942
+ */
2943
+ asset_type: 'webhook';
2944
+ /**
2945
+ * Webhook URL to call for dynamic content
2946
+ */
2947
+ url: string;
2948
+ method?: HTTPMethod;
2949
+ /**
2950
+ * Maximum time to wait for response in milliseconds
2951
+ * @minimum 10
2952
+ * @maximum 5000
2953
+ */
2954
+ timeout_ms?: number;
2955
+ /**
2956
+ * Universal macros that can be passed to webhook (e.g., DEVICE_TYPE, COUNTRY). See docs/creative/universal-macros.mdx for full list.
2957
+ */
2958
+ supported_macros?: (UniversalMacro | string)[];
2959
+ /**
2960
+ * Universal macros that must be provided for webhook to function
2961
+ */
2962
+ required_macros?: (UniversalMacro | string)[];
2963
+ response_type: WebhookResponseType;
2964
+ /**
2965
+ * Security configuration for webhook calls
2966
+ */
2967
+ security: {
2968
+ method: WebhookSecurityMethod;
2969
+ /**
2970
+ * Header name for HMAC signature (e.g., 'X-Signature')
2971
+ */
2972
+ hmac_header?: string;
2973
+ /**
2974
+ * Header name for API key (e.g., 'X-API-Key')
2975
+ */
2976
+ api_key_header?: string;
2977
+ };
2978
+ provenance?: Provenance;
2979
+ }
2980
+
2981
+ /**
2982
+ * Expected content type of webhook response
2983
+ */
2984
+ export type WebhookResponseType = 'html' | 'json' | 'xml' | 'javascript';
2985
+
2986
+ /**
2987
+ * Authentication method
2988
+ */
2989
+ export type WebhookSecurityMethod = 'hmac_sha256' | 'api_key' | 'none';
2990
+
2991
+ /**
2992
+ * 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).
2993
+ */
2994
+ export interface ZipAsset {
2995
+ /**
2996
+ * Discriminator identifying this as a zip-bundled asset. See /schemas/creative/asset-types for the registry.
2997
+ */
2998
+ asset_type: 'zip';
2999
+ /**
3000
+ * URL where the zip archive is hosted. Must be HTTPS.
3001
+ */
3002
+ url: string;
3003
+ /**
3004
+ * Maximum file size in kilobytes. Receivers should reject zips exceeding this.
3005
+ * @minimum 0
3006
+ */
3007
+ max_file_size_kb?: number;
3008
+ /**
3009
+ * Relative path to the entry file within the zip (typically 'index.html'). Receivers default to 'index.html' if absent.
3010
+ */
3011
+ entry_point?: string;
3012
+ /**
3013
+ * File extensions permitted inside the zip (e.g., ['html', 'css', 'js', 'png', 'jpg', 'svg', 'webp', 'json', 'woff2']). Receivers may reject zips containing other extensions.
3014
+ */
3015
+ allowed_inner_extensions?: string[];
3016
+ /**
3017
+ * Fallback image URL for environments that cannot render the bundled creative (e.g., non-HTML5 endpoints, ad blockers). Recommended for HTML5 banners.
3018
+ */
3019
+ backup_image_url?: string;
3020
+ /**
3021
+ * Optional SHA-256 content digest of the zip archive (sha256:<hex>) for integrity verification. Lets receivers detect tampered or stale archives.
3022
+ * @pattern ^sha256:[a-f0-9]{64}$
3023
+ */
3024
+ digest?: string;
3025
+ /**
3026
+ * Self-declared accessibility properties for this opaque creative
3027
+ */
3028
+ accessibility?: {
3029
+ /**
3030
+ * Text alternative describing the creative content
3031
+ */
3032
+ alt_text?: string;
3033
+ /**
3034
+ * Whether the creative can be fully operated via keyboard
3035
+ */
3036
+ keyboard_navigable?: boolean;
3037
+ /**
3038
+ * Whether the creative respects prefers-reduced-motion or provides pause/stop controls
3039
+ */
3040
+ motion_control?: boolean;
3041
+ /**
3042
+ * Whether the creative has been tested with screen readers
3043
+ */
3044
+ screen_reader_tested?: boolean;
3045
+ };
3046
+ provenance?: Provenance;
3047
+ }