@adcp/client 4.21.0 → 4.22.1

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 (160) hide show
  1. package/AGENTS.md +278 -0
  2. package/README.md +96 -61
  3. package/bin/adcp.js +342 -4
  4. package/dist/lib/agents/index.generated.d.ts +9 -1
  5. package/dist/lib/agents/index.generated.d.ts.map +1 -1
  6. package/dist/lib/agents/index.generated.js +12 -0
  7. package/dist/lib/agents/index.generated.js.map +1 -1
  8. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.d.ts +2 -1
  10. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  11. package/dist/lib/core/SingleAgentClient.js +10 -1
  12. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  13. package/dist/lib/discovery/property-crawler.d.ts +4 -0
  14. package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
  15. package/dist/lib/discovery/property-crawler.js +10 -2
  16. package/dist/lib/discovery/property-crawler.js.map +1 -1
  17. package/dist/lib/index.d.ts +4 -4
  18. package/dist/lib/index.d.ts.map +1 -1
  19. package/dist/lib/index.js +6 -4
  20. package/dist/lib/index.js.map +1 -1
  21. package/dist/lib/protocols/index.d.ts.map +1 -1
  22. package/dist/lib/protocols/index.js +8 -6
  23. package/dist/lib/protocols/index.js.map +1 -1
  24. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  25. package/dist/lib/protocols/mcp.js +24 -11
  26. package/dist/lib/protocols/mcp.js.map +1 -1
  27. package/dist/lib/server/index.d.ts +2 -0
  28. package/dist/lib/server/index.d.ts.map +1 -1
  29. package/dist/lib/server/index.js +3 -1
  30. package/dist/lib/server/index.js.map +1 -1
  31. package/dist/lib/server/serve.d.ts +73 -0
  32. package/dist/lib/server/serve.d.ts.map +1 -0
  33. package/dist/lib/server/serve.js +94 -0
  34. package/dist/lib/server/serve.js.map +1 -0
  35. package/dist/lib/testing/client.d.ts.map +1 -1
  36. package/dist/lib/testing/client.js +1 -0
  37. package/dist/lib/testing/client.js.map +1 -1
  38. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  39. package/dist/lib/testing/compliance/comply.js +48 -63
  40. package/dist/lib/testing/compliance/comply.js.map +1 -1
  41. package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
  42. package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
  43. package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
  44. package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
  45. package/dist/lib/testing/compliance/types.d.ts +1 -1
  46. package/dist/lib/testing/compliance/types.d.ts.map +1 -1
  47. package/dist/lib/testing/index.d.ts +1 -0
  48. package/dist/lib/testing/index.d.ts.map +1 -1
  49. package/dist/lib/testing/index.js +23 -1
  50. package/dist/lib/testing/index.js.map +1 -1
  51. package/dist/lib/testing/orchestrator.d.ts +8 -0
  52. package/dist/lib/testing/orchestrator.d.ts.map +1 -1
  53. package/dist/lib/testing/orchestrator.js +8 -0
  54. package/dist/lib/testing/orchestrator.js.map +1 -1
  55. package/dist/lib/testing/storyboard/context.d.ts +34 -0
  56. package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
  57. package/dist/lib/testing/storyboard/context.js +257 -0
  58. package/dist/lib/testing/storyboard/context.js.map +1 -0
  59. package/dist/lib/testing/storyboard/index.d.ts +15 -0
  60. package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
  61. package/dist/lib/testing/storyboard/index.js +48 -0
  62. package/dist/lib/testing/storyboard/index.js.map +1 -0
  63. package/dist/lib/testing/storyboard/loader.d.ts +53 -0
  64. package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
  65. package/dist/lib/testing/storyboard/loader.js +114 -0
  66. package/dist/lib/testing/storyboard/loader.js.map +1 -0
  67. package/dist/lib/testing/storyboard/path.d.ts +29 -0
  68. package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
  69. package/dist/lib/testing/storyboard/path.js +121 -0
  70. package/dist/lib/testing/storyboard/path.js.map +1 -0
  71. package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
  72. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
  73. package/dist/lib/testing/storyboard/request-builder.js +410 -0
  74. package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
  75. package/dist/lib/testing/storyboard/runner.d.ts +24 -0
  76. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
  77. package/dist/lib/testing/storyboard/runner.js +280 -0
  78. package/dist/lib/testing/storyboard/runner.js.map +1 -0
  79. package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
  80. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
  81. package/dist/lib/testing/storyboard/task-map.js +84 -0
  82. package/dist/lib/testing/storyboard/task-map.js.map +1 -0
  83. package/dist/lib/testing/storyboard/types.d.ts +156 -0
  84. package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
  85. package/dist/lib/testing/storyboard/types.js +10 -0
  86. package/dist/lib/testing/storyboard/types.js.map +1 -0
  87. package/dist/lib/testing/storyboard/validations.d.ts +17 -0
  88. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
  89. package/dist/lib/testing/storyboard/validations.js +166 -0
  90. package/dist/lib/testing/storyboard/validations.js.map +1 -0
  91. package/dist/lib/testing/types.d.ts +2 -0
  92. package/dist/lib/testing/types.d.ts.map +1 -1
  93. package/dist/lib/types/core.generated.d.ts +2 -2
  94. package/dist/lib/types/core.generated.d.ts.map +1 -1
  95. package/dist/lib/types/core.generated.js +1 -1
  96. package/dist/lib/types/schemas.generated.d.ts +193 -34
  97. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  98. package/dist/lib/types/schemas.generated.js +87 -5
  99. package/dist/lib/types/schemas.generated.js.map +1 -1
  100. package/dist/lib/types/tools.generated.d.ts +280 -3
  101. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  102. package/dist/lib/utils/response-schemas.d.ts.map +1 -1
  103. package/dist/lib/utils/response-schemas.js +34 -3
  104. package/dist/lib/utils/response-schemas.js.map +1 -1
  105. package/dist/lib/utils/validate-user-agent.d.ts +8 -0
  106. package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
  107. package/dist/lib/utils/validate-user-agent.js +15 -0
  108. package/dist/lib/utils/validate-user-agent.js.map +1 -0
  109. package/dist/lib/version.d.ts +6 -0
  110. package/dist/lib/version.d.ts.map +1 -1
  111. package/dist/lib/version.js +7 -1
  112. package/dist/lib/version.js.map +1 -1
  113. package/docs/README.md +42 -0
  114. package/docs/guides/BUILD-AN-AGENT.md +294 -0
  115. package/docs/llms.txt +634 -0
  116. package/examples/README.md +106 -0
  117. package/examples/adcp.config.json +30 -0
  118. package/examples/basic-a2a.ts +76 -0
  119. package/examples/basic-mcp.ts +50 -0
  120. package/examples/batch-preview-test.ts +266 -0
  121. package/examples/conversation-client.ts +291 -0
  122. package/examples/debug-preview-response.ts +73 -0
  123. package/examples/debug-preview-with-logging.ts +50 -0
  124. package/examples/easy-config-demo.ts +242 -0
  125. package/examples/env-config.ts +51 -0
  126. package/examples/error-compliant-server.ts +237 -0
  127. package/examples/generative-creative-demo.ts +205 -0
  128. package/examples/inspect-card-formats.ts +161 -0
  129. package/examples/logger-usage.ts +165 -0
  130. package/examples/oauth-cli-example.ts +154 -0
  131. package/examples/pr78-async-patterns-demo.ts +247 -0
  132. package/examples/signals-agent.ts +163 -0
  133. package/examples/simple-getting-started.ts +225 -0
  134. package/examples/simple-protocol-demo.ts +75 -0
  135. package/examples/test-helpers-demo.ts +239 -0
  136. package/examples/zod-validation-example.ts +126 -0
  137. package/package.json +12 -2
  138. package/skills/adcp/SKILL.md +13 -2
  139. package/storyboards/audience_sync.yaml +199 -0
  140. package/storyboards/behavioral_analysis.yaml +244 -0
  141. package/storyboards/brand_rights.yaml +131 -0
  142. package/storyboards/creative_ad_server.yaml +171 -0
  143. package/storyboards/creative_sales_agent.yaml +169 -0
  144. package/storyboards/creative_template.yaml +306 -0
  145. package/storyboards/deterministic_testing.yaml +925 -0
  146. package/storyboards/error_compliance.yaml +231 -0
  147. package/storyboards/governance_content_standards.yaml +213 -0
  148. package/storyboards/governance_property_lists.yaml +372 -0
  149. package/storyboards/media_buy_catalog_creative.yaml +457 -0
  150. package/storyboards/media_buy_governance_escalation.yaml +467 -0
  151. package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
  152. package/storyboards/media_buy_non_guaranteed.yaml +288 -0
  153. package/storyboards/media_buy_proposal_mode.yaml +369 -0
  154. package/storyboards/media_buy_seller.yaml +560 -0
  155. package/storyboards/media_buy_state_machine.yaml +254 -0
  156. package/storyboards/schema.yaml +65 -0
  157. package/storyboards/schema_validation.yaml +166 -0
  158. package/storyboards/si_session.yaml +384 -0
  159. package/storyboards/signal_marketplace.yaml +283 -0
  160. package/storyboards/signal_owned.yaml +211 -0
@@ -0,0 +1,369 @@
1
+ id: media_buy_proposal_mode
2
+ version: "1.0.0"
3
+ title: "Media buy via proposal acceptance"
4
+ category: media_buy_proposal_mode
5
+ summary: "Seller agent that generates curated media plan proposals the buyer can review, refine, and accept."
6
+ platform_types:
7
+ - dsp
8
+ - retail_media
9
+ - pmax_platform
10
+ - generative_dsp
11
+
12
+ track: media_buy
13
+ required_tools:
14
+ - create_media_buy
15
+ - get_products
16
+ narrative: |
17
+ Your seller generates curated media plan proposals. The buyer sends a brief, your platform
18
+ returns products alongside proposals — curated bundles with budget allocations and rationale
19
+ for each recommendation. The buyer reviews, optionally refines, and then accepts a proposal
20
+ as-is instead of manually building packages.
21
+
22
+ Proposal mode is the recommended flow for buyers who trust the seller's product
23
+ recommendations. Instead of the buyer cherry-picking individual products and assembling
24
+ packages, the seller's AI builds an optimized media plan that the buyer can accept with a
25
+ single call.
26
+
27
+ This storyboard walks through the proposal lifecycle: brief, proposal generation, optional
28
+ refinement, acceptance, creative sync, and delivery monitoring.
29
+
30
+ agent:
31
+ interaction_model: media_buy_seller
32
+ capabilities:
33
+ - sells_media
34
+ - accepts_briefs
35
+ - generates_proposals
36
+ examples:
37
+ - "Full-service publisher with AI planning"
38
+ - "Retail media network with curated packages"
39
+ - "Premium video platform with proposal engine"
40
+
41
+ caller:
42
+ role: buyer_agent
43
+ example: "Pinnacle Agency (buyer)"
44
+
45
+ prerequisites:
46
+ description: |
47
+ The caller needs a brand identity and operator credentials for account setup.
48
+ The test kit provides a sample brand (Acme Outdoor) with campaign parameters
49
+ suitable for testing the proposal acceptance flow.
50
+ test_kit: "test-kits/acme-outdoor.yaml"
51
+
52
+ phases:
53
+ - id: account_setup
54
+ title: "Account setup"
55
+ narrative: |
56
+ The buyer establishes an account relationship with your platform before
57
+ requesting proposals.
58
+
59
+ steps:
60
+ - id: sync_accounts
61
+ title: "Establish account relationship"
62
+ narrative: |
63
+ The buyer registers their brand and operator with your platform.
64
+ task: sync_accounts
65
+ schema_ref: "account/sync-accounts-request.json"
66
+ response_schema_ref: "account/sync-accounts-response.json"
67
+ doc_ref: "/accounts/tasks/sync_accounts"
68
+ stateful: true
69
+ expected: |
70
+ Return the account with:
71
+ - account_id: your platform's identifier for this relationship
72
+ - action: created or updated
73
+ - status: active or pending_approval
74
+ - payment_terms: net_30, prepay, etc.
75
+
76
+ sample_request:
77
+ accounts:
78
+ - brand:
79
+ domain: "acmeoutdoor.com"
80
+ operator: "pinnacle-agency.com"
81
+ billing: "operator"
82
+ payment_terms: "net_30"
83
+
84
+ validations:
85
+ - check: response_schema
86
+ description: "Response matches sync-accounts-response.json schema"
87
+ - check: field_present
88
+ path: "accounts[0].account_id"
89
+ description: "Account has a platform-assigned ID"
90
+
91
+ - id: brief_with_proposals
92
+ title: "Brief with proposals"
93
+ narrative: |
94
+ The buyer sends a brief. Your platform returns products and — because you support
95
+ proposal mode — also returns proposals: curated media plans with budget allocations,
96
+ product selections, and rationale for each recommendation. The buyer can review
97
+ multiple proposals side by side.
98
+
99
+ steps:
100
+ - id: get_products_brief
101
+ title: "Send a brief and receive proposals"
102
+ narrative: |
103
+ The buyer describes what they want. Your platform returns products alongside
104
+ one or more proposals. Each proposal bundles products with budget allocations
105
+ and explains why those products were selected and how the budget was distributed.
106
+
107
+ Proposals give the buyer a ready-to-accept media plan instead of requiring
108
+ manual package assembly.
109
+ task: get_products
110
+ schema_ref: "media-buy/get-products-request.json"
111
+ response_schema_ref: "media-buy/get-products-response.json"
112
+ doc_ref: "/media-buy/task-reference/get_products"
113
+ stateful: false
114
+ expected: |
115
+ Return products and proposals matching the brief:
116
+ - products: individual products with pricing and forecasts
117
+ - proposals: curated media plans, each containing:
118
+ - proposal_id: unique identifier for this proposal
119
+ - name: descriptive label (e.g., "Balanced Reach Plan")
120
+ - budget_allocations: how the total budget is split across products
121
+ - rationale: why these products were selected and how the budget was distributed
122
+ - total_budget: sum of allocations
123
+ - forecast: aggregate impressions, reach, frequency
124
+
125
+ sample_request:
126
+ buying_mode: "brief"
127
+ brief: "Premium video and display across outdoor lifestyle and sports. Q2 flight, $50K total budget. Adults 25-54, US and Canada. Looking for a balanced plan across CTV, online video, and display."
128
+ brand:
129
+ domain: "acmeoutdoor.com"
130
+ account:
131
+ brand:
132
+ domain: "acmeoutdoor.com"
133
+ operator: "pinnacle-agency.com"
134
+
135
+ validations:
136
+ - check: response_schema
137
+ description: "Response matches get-products-response.json schema"
138
+ - check: field_present
139
+ path: "products"
140
+ description: "Response contains a products array"
141
+ - check: field_present
142
+ path: "proposals"
143
+ description: "Response contains a proposals array"
144
+ - check: field_present
145
+ path: "proposals[0].proposal_id"
146
+ description: "Each proposal has a proposal_id"
147
+
148
+ - id: review_refine
149
+ title: "Refine a proposal"
150
+ narrative: |
151
+ The buyer reviews the proposals and wants to adjust one. They call get_products
152
+ in refine mode targeting a specific proposal_id. The refinement might adjust
153
+ budget splits, swap a product, or add constraints. Your platform returns the
154
+ updated proposal.
155
+
156
+ steps:
157
+ - id: get_products_refine
158
+ title: "Refine a specific proposal"
159
+ narrative: |
160
+ The buyer targets a specific proposal for refinement. They reference the
161
+ proposal_id and describe what they want to change. Your platform applies
162
+ the refinements to that proposal and returns the updated version.
163
+ task: get_products
164
+ schema_ref: "media-buy/get-products-request.json"
165
+ response_schema_ref: "media-buy/get-products-response.json"
166
+ doc_ref: "/media-buy/task-reference/get_products"
167
+ stateful: true
168
+ expected: |
169
+ Return the refined proposal:
170
+ - proposals: updated proposal reflecting the requested changes
171
+ - refinement_applied: how each refinement was handled
172
+ - Updated budget allocations, product selections, and forecasts
173
+ - products: updated product set if products were swapped
174
+
175
+ sample_request:
176
+ buying_mode: "refine"
177
+ refine:
178
+ - scope: "proposal"
179
+ proposal_id: "balanced_reach_q2"
180
+ ask: "Shift 60% of budget to CTV. Drop the display product and redistribute that budget to video."
181
+ - scope: "request"
182
+ ask: "All products must support frequency capping at 3 per day."
183
+ brand:
184
+ domain: "acmeoutdoor.com"
185
+ account:
186
+ brand:
187
+ domain: "acmeoutdoor.com"
188
+ operator: "pinnacle-agency.com"
189
+
190
+ validations:
191
+ - check: response_schema
192
+ description: "Response matches get-products-response.json schema"
193
+ - check: field_present
194
+ path: "proposals"
195
+ description: "Response contains updated proposals"
196
+
197
+ - id: accept_proposal
198
+ title: "Accept the proposal"
199
+ narrative: |
200
+ The buyer is satisfied with the refined proposal and accepts it by creating a
201
+ media buy with the proposal_id. Instead of specifying individual packages, the
202
+ buyer passes the proposal_id and total_budget. Your platform converts the proposal
203
+ into a confirmed media buy with the exact product selections and budget allocations
204
+ from the proposal.
205
+
206
+ steps:
207
+ - id: create_media_buy
208
+ title: "Create a media buy from proposal"
209
+ narrative: |
210
+ The buyer accepts a proposal by passing proposal_id to create_media_buy. The
211
+ buyer does NOT specify a packages array — the platform uses the proposal's
212
+ product selections and budget allocations to build the packages automatically.
213
+
214
+ This is the key difference from manual package creation: the buyer trusts the
215
+ seller's recommendation and accepts the plan as-is.
216
+ task: create_media_buy
217
+ schema_ref: "media-buy/create-media-buy-request.json"
218
+ response_schema_ref: "media-buy/create-media-buy-response.json"
219
+ doc_ref: "/media-buy/task-reference/create_media_buy"
220
+ stateful: true
221
+ expected: |
222
+ Convert the proposal into a confirmed media buy:
223
+ - media_buy_id: your platform's identifier
224
+ - status: confirmed or active
225
+ - confirmed_at: timestamp
226
+ - packages: line items derived from the proposal's budget allocations
227
+ - proposal_id: echoed back to confirm which proposal was accepted
228
+ - valid_actions: creative sync, pause, get_delivery
229
+
230
+ sample_request:
231
+ account:
232
+ brand:
233
+ domain: "acmeoutdoor.com"
234
+ operator: "pinnacle-agency.com"
235
+ brand:
236
+ domain: "acmeoutdoor.com"
237
+ proposal_id: "balanced_reach_q2"
238
+ total_budget: 50000
239
+ start_time: "2026-04-01T00:00:00Z"
240
+ end_time: "2026-06-30T23:59:59Z"
241
+
242
+ validations:
243
+ - check: response_schema
244
+ description: "Response matches create-media-buy-response.json schema"
245
+
246
+ - id: creative_sync
247
+ title: "Creative sync"
248
+ narrative: |
249
+ With the proposal accepted and the media buy confirmed, the buyer syncs creative
250
+ assets. The buyer first checks what formats the accepted products require, then
251
+ pushes matching creative assets.
252
+
253
+ steps:
254
+ - id: list_formats
255
+ title: "Check creative format requirements"
256
+ narrative: |
257
+ The buyer confirms what creative formats the accepted proposal's products
258
+ require. Your platform returns format specs with asset requirements.
259
+ task: list_creative_formats
260
+ schema_ref: "creative/list-creative-formats-request.json"
261
+ response_schema_ref: "creative/list-creative-formats-response.json"
262
+ doc_ref: "/creative/task-reference/list_creative_formats"
263
+ stateful: false
264
+ expected: |
265
+ Return creative formats your platform accepts. Each format should define:
266
+ - format_id with your agent_url and unique id
267
+ - Asset requirements (dimensions, file sizes, mime types)
268
+ - Render dimensions
269
+
270
+ sample_request: {}
271
+
272
+ validations:
273
+ - check: response_schema
274
+ description: "Response matches list-creative-formats-response.json schema"
275
+ - check: field_present
276
+ path: "formats"
277
+ description: "Response contains formats array"
278
+
279
+ - id: sync_creatives
280
+ title: "Push creative assets"
281
+ narrative: |
282
+ The buyer uploads creative assets for the products in the accepted proposal.
283
+ Your platform validates each creative against the format specs and returns
284
+ per-creative status.
285
+ task: sync_creatives
286
+ schema_ref: "creative/sync-creatives-request.json"
287
+ response_schema_ref: "creative/sync-creatives-response.json"
288
+ doc_ref: "/creative/task-reference/sync_creatives"
289
+ stateful: true
290
+ expected: |
291
+ Accept and validate creatives:
292
+ - Per-creative action: created or updated
293
+ - Per-creative status: accepted, pending_review, or rejected
294
+ - Validation errors for rejected creatives
295
+
296
+ sample_request:
297
+ account:
298
+ brand:
299
+ domain: "acmeoutdoor.com"
300
+ operator: "pinnacle-agency.com"
301
+ creatives:
302
+ - creative_id: "video_30s_trail_pro"
303
+ name: "Trail Pro 3000 - 30s CTV Spot"
304
+ format_id:
305
+ agent_url: "https://your-platform.example.com"
306
+ id: "ssai_30s"
307
+ assets:
308
+ - asset_id: "video"
309
+ asset_type: "video"
310
+ url: "https://cdn.pinnacle-agency.example/trail-pro-30s.mp4"
311
+ mime_type: "video/mp4"
312
+ - creative_id: "video_15s_trail_pro"
313
+ name: "Trail Pro 3000 - 15s Online Video"
314
+ format_id:
315
+ agent_url: "https://your-platform.example.com"
316
+ id: "preroll_15s"
317
+ assets:
318
+ - asset_id: "video"
319
+ asset_type: "video"
320
+ url: "https://cdn.pinnacle-agency.example/trail-pro-15s.mp4"
321
+ mime_type: "video/mp4"
322
+
323
+ validations:
324
+ - check: response_schema
325
+ description: "Response matches sync-creatives-response.json schema"
326
+ - check: field_present
327
+ path: "creatives[0].action"
328
+ description: "Each creative has an action (created/updated)"
329
+
330
+ - id: delivery
331
+ title: "Delivery and reporting"
332
+ narrative: |
333
+ The campaign from the accepted proposal is live. The buyer monitors delivery
334
+ to verify the proposal's forecasts are tracking.
335
+
336
+ steps:
337
+ - id: get_delivery
338
+ title: "Check delivery metrics"
339
+ narrative: |
340
+ The buyer requests delivery data for the media buy created from the proposal.
341
+ Your platform returns performance metrics that the buyer can compare against
342
+ the proposal's original forecasts.
343
+ task: get_media_buy_delivery
344
+ schema_ref: "media-buy/get-media-buy-delivery-request.json"
345
+ response_schema_ref: "media-buy/get-media-buy-delivery-response.json"
346
+ doc_ref: "/media-buy/task-reference/get_media_buy_delivery"
347
+ stateful: true
348
+ expected: |
349
+ Return delivery metrics for the media buy:
350
+ - Per-package delivery: impressions, clicks, spend, completion rates
351
+ - Pacing against the proposal's original forecast
352
+ - Budget utilization: spent vs. committed per package
353
+ - Daily breakdown if requested
354
+
355
+ sample_request:
356
+ account:
357
+ brand:
358
+ domain: "acmeoutdoor.com"
359
+ operator: "pinnacle-agency.com"
360
+ media_buy_ids:
361
+ - "mb_acme_q2_2026_proposal"
362
+ include_package_daily_breakdown: true
363
+
364
+ validations:
365
+ - check: response_schema
366
+ description: "Response matches get-media-buy-delivery-response.json schema"
367
+ - check: field_present
368
+ path: "media_buys"
369
+ description: "Response contains media buy delivery data"