@adcp/client 4.20.0 → 4.22.0

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 (210) 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 +9 -9
  18. package/dist/lib/index.d.ts.map +1 -1
  19. package/dist/lib/index.js +13 -5
  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/registry/cursor-store.d.ts +19 -0
  28. package/dist/lib/registry/cursor-store.d.ts.map +1 -0
  29. package/dist/lib/registry/cursor-store.js +44 -0
  30. package/dist/lib/registry/cursor-store.js.map +1 -0
  31. package/dist/lib/registry/index.d.ts +21 -3
  32. package/dist/lib/registry/index.d.ts.map +1 -1
  33. package/dist/lib/registry/index.js +94 -1
  34. package/dist/lib/registry/index.js.map +1 -1
  35. package/dist/lib/registry/property-registry.d.ts +57 -0
  36. package/dist/lib/registry/property-registry.d.ts.map +1 -0
  37. package/dist/lib/registry/property-registry.js +92 -0
  38. package/dist/lib/registry/property-registry.js.map +1 -0
  39. package/dist/lib/registry/sync.d.ts +4 -0
  40. package/dist/lib/registry/sync.d.ts.map +1 -1
  41. package/dist/lib/registry/sync.js +14 -0
  42. package/dist/lib/registry/sync.js.map +1 -1
  43. package/dist/lib/registry/types.d.ts +35 -2
  44. package/dist/lib/registry/types.d.ts.map +1 -1
  45. package/dist/lib/registry/types.generated.d.ts +349 -321
  46. package/dist/lib/registry/types.generated.d.ts.map +1 -1
  47. package/dist/lib/registry/types.generated.js +1 -1
  48. package/dist/lib/server/index.d.ts +2 -0
  49. package/dist/lib/server/index.d.ts.map +1 -1
  50. package/dist/lib/server/index.js +3 -1
  51. package/dist/lib/server/index.js.map +1 -1
  52. package/dist/lib/server/serve.d.ts +45 -0
  53. package/dist/lib/server/serve.d.ts.map +1 -0
  54. package/dist/lib/server/serve.js +86 -0
  55. package/dist/lib/server/serve.js.map +1 -0
  56. package/dist/lib/testing/agent-tester.d.ts +1 -1
  57. package/dist/lib/testing/agent-tester.d.ts.map +1 -1
  58. package/dist/lib/testing/agent-tester.js +10 -1
  59. package/dist/lib/testing/agent-tester.js.map +1 -1
  60. package/dist/lib/testing/client.d.ts.map +1 -1
  61. package/dist/lib/testing/client.js +3 -0
  62. package/dist/lib/testing/client.js.map +1 -1
  63. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  64. package/dist/lib/testing/compliance/comply.js +158 -203
  65. package/dist/lib/testing/compliance/comply.js.map +1 -1
  66. package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
  67. package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
  68. package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
  69. package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
  70. package/dist/lib/testing/compliance/types.d.ts +1 -1
  71. package/dist/lib/testing/compliance/types.d.ts.map +1 -1
  72. package/dist/lib/testing/index.d.ts +2 -1
  73. package/dist/lib/testing/index.d.ts.map +1 -1
  74. package/dist/lib/testing/index.js +26 -1
  75. package/dist/lib/testing/index.js.map +1 -1
  76. package/dist/lib/testing/orchestrator.d.ts +8 -0
  77. package/dist/lib/testing/orchestrator.d.ts.map +1 -1
  78. package/dist/lib/testing/orchestrator.js +11 -0
  79. package/dist/lib/testing/orchestrator.js.map +1 -1
  80. package/dist/lib/testing/scenarios/brand-rights.d.ts +23 -0
  81. package/dist/lib/testing/scenarios/brand-rights.d.ts.map +1 -0
  82. package/dist/lib/testing/scenarios/brand-rights.js +144 -0
  83. package/dist/lib/testing/scenarios/brand-rights.js.map +1 -0
  84. package/dist/lib/testing/scenarios/capabilities.d.ts.map +1 -1
  85. package/dist/lib/testing/scenarios/capabilities.js +11 -2
  86. package/dist/lib/testing/scenarios/capabilities.js.map +1 -1
  87. package/dist/lib/testing/scenarios/governance.d.ts.map +1 -1
  88. package/dist/lib/testing/scenarios/governance.js +5 -0
  89. package/dist/lib/testing/scenarios/governance.js.map +1 -1
  90. package/dist/lib/testing/scenarios/index.d.ts +2 -0
  91. package/dist/lib/testing/scenarios/index.d.ts.map +1 -1
  92. package/dist/lib/testing/scenarios/index.js +10 -2
  93. package/dist/lib/testing/scenarios/index.js.map +1 -1
  94. package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -1
  95. package/dist/lib/testing/scenarios/media-buy.js +22 -3
  96. package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
  97. package/dist/lib/testing/scenarios/trusted-match.d.ts +22 -0
  98. package/dist/lib/testing/scenarios/trusted-match.d.ts.map +1 -0
  99. package/dist/lib/testing/scenarios/trusted-match.js +128 -0
  100. package/dist/lib/testing/scenarios/trusted-match.js.map +1 -0
  101. package/dist/lib/testing/storyboard/context.d.ts +34 -0
  102. package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
  103. package/dist/lib/testing/storyboard/context.js +257 -0
  104. package/dist/lib/testing/storyboard/context.js.map +1 -0
  105. package/dist/lib/testing/storyboard/index.d.ts +15 -0
  106. package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
  107. package/dist/lib/testing/storyboard/index.js +48 -0
  108. package/dist/lib/testing/storyboard/index.js.map +1 -0
  109. package/dist/lib/testing/storyboard/loader.d.ts +53 -0
  110. package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
  111. package/dist/lib/testing/storyboard/loader.js +114 -0
  112. package/dist/lib/testing/storyboard/loader.js.map +1 -0
  113. package/dist/lib/testing/storyboard/path.d.ts +29 -0
  114. package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
  115. package/dist/lib/testing/storyboard/path.js +121 -0
  116. package/dist/lib/testing/storyboard/path.js.map +1 -0
  117. package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
  118. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
  119. package/dist/lib/testing/storyboard/request-builder.js +410 -0
  120. package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
  121. package/dist/lib/testing/storyboard/runner.d.ts +24 -0
  122. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
  123. package/dist/lib/testing/storyboard/runner.js +280 -0
  124. package/dist/lib/testing/storyboard/runner.js.map +1 -0
  125. package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
  126. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
  127. package/dist/lib/testing/storyboard/task-map.js +84 -0
  128. package/dist/lib/testing/storyboard/task-map.js.map +1 -0
  129. package/dist/lib/testing/storyboard/types.d.ts +156 -0
  130. package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
  131. package/dist/lib/testing/storyboard/types.js +10 -0
  132. package/dist/lib/testing/storyboard/types.js.map +1 -0
  133. package/dist/lib/testing/storyboard/validations.d.ts +17 -0
  134. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
  135. package/dist/lib/testing/storyboard/validations.js +166 -0
  136. package/dist/lib/testing/storyboard/validations.js.map +1 -0
  137. package/dist/lib/testing/types.d.ts +4 -1
  138. package/dist/lib/testing/types.d.ts.map +1 -1
  139. package/dist/lib/types/core.generated.d.ts +36 -23
  140. package/dist/lib/types/core.generated.d.ts.map +1 -1
  141. package/dist/lib/types/core.generated.js +1 -1
  142. package/dist/lib/types/schemas.generated.d.ts +1098 -770
  143. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  144. package/dist/lib/types/schemas.generated.js +163 -76
  145. package/dist/lib/types/schemas.generated.js.map +1 -1
  146. package/dist/lib/types/tools.generated.d.ts +314 -24
  147. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  148. package/dist/lib/utils/capabilities.d.ts +4 -1
  149. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  150. package/dist/lib/utils/capabilities.js +25 -1
  151. package/dist/lib/utils/capabilities.js.map +1 -1
  152. package/dist/lib/utils/response-schemas.d.ts.map +1 -1
  153. package/dist/lib/utils/response-schemas.js +34 -3
  154. package/dist/lib/utils/response-schemas.js.map +1 -1
  155. package/dist/lib/utils/validate-user-agent.d.ts +8 -0
  156. package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
  157. package/dist/lib/utils/validate-user-agent.js +15 -0
  158. package/dist/lib/utils/validate-user-agent.js.map +1 -0
  159. package/dist/lib/version.d.ts +9 -3
  160. package/dist/lib/version.d.ts.map +1 -1
  161. package/dist/lib/version.js +10 -4
  162. package/dist/lib/version.js.map +1 -1
  163. package/docs/README.md +42 -0
  164. package/docs/guides/BUILD-AN-AGENT.md +292 -0
  165. package/docs/llms.txt +634 -0
  166. package/examples/README.md +106 -0
  167. package/examples/adcp.config.json +30 -0
  168. package/examples/basic-a2a.ts +76 -0
  169. package/examples/basic-mcp.ts +50 -0
  170. package/examples/batch-preview-test.ts +266 -0
  171. package/examples/conversation-client.ts +291 -0
  172. package/examples/debug-preview-response.ts +73 -0
  173. package/examples/debug-preview-with-logging.ts +50 -0
  174. package/examples/easy-config-demo.ts +242 -0
  175. package/examples/env-config.ts +51 -0
  176. package/examples/error-compliant-server.ts +237 -0
  177. package/examples/generative-creative-demo.ts +205 -0
  178. package/examples/inspect-card-formats.ts +161 -0
  179. package/examples/logger-usage.ts +165 -0
  180. package/examples/oauth-cli-example.ts +154 -0
  181. package/examples/pr78-async-patterns-demo.ts +247 -0
  182. package/examples/signals-agent.ts +162 -0
  183. package/examples/simple-getting-started.ts +225 -0
  184. package/examples/simple-protocol-demo.ts +75 -0
  185. package/examples/test-helpers-demo.ts +239 -0
  186. package/examples/zod-validation-example.ts +126 -0
  187. package/package.json +12 -2
  188. package/skills/adcp/SKILL.md +13 -2
  189. package/storyboards/audience_sync.yaml +199 -0
  190. package/storyboards/behavioral_analysis.yaml +244 -0
  191. package/storyboards/brand_rights.yaml +131 -0
  192. package/storyboards/creative_ad_server.yaml +171 -0
  193. package/storyboards/creative_sales_agent.yaml +169 -0
  194. package/storyboards/creative_template.yaml +306 -0
  195. package/storyboards/deterministic_testing.yaml +925 -0
  196. package/storyboards/error_compliance.yaml +231 -0
  197. package/storyboards/governance_content_standards.yaml +213 -0
  198. package/storyboards/governance_property_lists.yaml +372 -0
  199. package/storyboards/media_buy_catalog_creative.yaml +457 -0
  200. package/storyboards/media_buy_governance_escalation.yaml +467 -0
  201. package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
  202. package/storyboards/media_buy_non_guaranteed.yaml +288 -0
  203. package/storyboards/media_buy_proposal_mode.yaml +369 -0
  204. package/storyboards/media_buy_seller.yaml +560 -0
  205. package/storyboards/media_buy_state_machine.yaml +254 -0
  206. package/storyboards/schema.yaml +65 -0
  207. package/storyboards/schema_validation.yaml +166 -0
  208. package/storyboards/si_session.yaml +384 -0
  209. package/storyboards/signal_marketplace.yaml +283 -0
  210. package/storyboards/signal_owned.yaml +211 -0
@@ -0,0 +1,560 @@
1
+ id: media_buy_seller
2
+ version: '1.0.0'
3
+ title: 'Media buy seller agent'
4
+ category: media_buy_seller
5
+ summary: 'Seller agent that receives briefs, returns products, accepts media buys, and reports delivery.'
6
+ platform_types:
7
+ - display_ad_server
8
+ - video_ad_server
9
+ - social_platform
10
+ - retail_media
11
+ - search_platform
12
+ - audio_platform
13
+ - linear_tv_platform
14
+ - dsp
15
+ - pmax_platform
16
+ - ai_ad_network
17
+ - ai_platform
18
+ - generative_dsp
19
+
20
+ track: reporting
21
+ required_tools:
22
+ - get_media_buy_delivery
23
+ narrative: |
24
+ You run a sell-side platform — a publisher, SSP, retail media network, or any system that
25
+ sells advertising inventory. A buyer agent connects to discover your products, negotiate
26
+ proposals, create media buys, and monitor delivery. Your agent handles the full lifecycle
27
+ from brief to reporting.
28
+
29
+ The buyer starts by setting up an account and optionally registering governance agents.
30
+ Then they send a natural-language brief, refine the resulting products, create a media buy,
31
+ sync creatives, and monitor delivery — all through AdCP tasks.
32
+
33
+ This storyboard walks through the complete media buy flow from the buyer's perspective,
34
+ including async operations and human-in-the-loop approval gates.
35
+
36
+ agent:
37
+ interaction_model: media_buy_seller
38
+ capabilities:
39
+ - sells_media
40
+ - accepts_briefs
41
+ - supports_guaranteed
42
+ - supports_non_guaranteed
43
+ examples:
44
+ - 'Yahoo'
45
+ - 'Retail media networks'
46
+ - 'Publisher platforms'
47
+ - 'SSPs'
48
+
49
+ caller:
50
+ role: buyer_agent
51
+ example: 'Scope3 (DSP)'
52
+
53
+ prerequisites:
54
+ description: |
55
+ The caller needs a brand identity and operator credentials for account setup.
56
+ The test kit provides a sample brand (Acme Outdoor) with campaign parameters
57
+ suitable for testing the full media buy flow.
58
+ test_kit: 'test-kits/acme-outdoor.yaml'
59
+
60
+ phases:
61
+ - id: account_setup
62
+ title: 'Account setup'
63
+ narrative: |
64
+ Before buying anything, the buyer establishes an account relationship with
65
+ your platform. This is the handshake: the buyer tells you which brand and
66
+ agency (operator) they represent, and you return an account ID, status, and
67
+ any setup requirements.
68
+
69
+ Some platforms approve accounts instantly. Others require human review — the
70
+ buyer gets back a pending_approval status and a URL to complete setup. The
71
+ buyer polls or waits for a webhook until the account is active.
72
+
73
+ steps:
74
+ - id: sync_accounts
75
+ title: 'Establish account relationship'
76
+ narrative: |
77
+ The buyer registers their brand and operator with your platform. This is
78
+ the first call in any new relationship. Your platform validates the request,
79
+ provisions the account, and returns its status.
80
+
81
+ If your platform requires manual approval (credit checks, sales team review),
82
+ return pending_approval with a setup URL. The buyer will complete setup there
83
+ and poll list_accounts until the status changes to active.
84
+ task: sync_accounts
85
+ schema_ref: 'account/sync-accounts-request.json'
86
+ response_schema_ref: 'account/sync-accounts-response.json'
87
+ doc_ref: '/accounts/tasks/sync_accounts'
88
+ comply_scenario: account_setup
89
+ stateful: true
90
+ expected: |
91
+ Return the account with:
92
+ - account_id: your platform's identifier for this relationship
93
+ - action: created or updated
94
+ - status: active (instant approval) or pending_approval (requires human review)
95
+ - account_scope: operator, brand, operator_brand, or agent
96
+ - setup: URL and message if pending_approval (where the human completes onboarding)
97
+ - rate_card: pricing tiers if applicable
98
+ - payment_terms: net_30, prepay, etc.
99
+
100
+ sample_request:
101
+ accounts:
102
+ - brand:
103
+ domain: 'acmeoutdoor.com'
104
+ operator: 'pinnacle-agency.com'
105
+ billing: 'operator'
106
+ payment_terms: 'net_30'
107
+
108
+ validations:
109
+ - check: response_schema
110
+ description: 'Response matches sync-accounts-response.json schema'
111
+ - check: field_present
112
+ path: 'accounts[0].account_id'
113
+ description: 'Account has a platform-assigned ID'
114
+ - check: field_present
115
+ path: 'accounts[0].status'
116
+ description: 'Account has a status (active or pending_approval)'
117
+
118
+ - id: governance_setup
119
+ title: 'Governance agent registration'
120
+ narrative: |
121
+ The buyer registers their governance agent with your platform. This tells your
122
+ platform where to call check_governance before confirming media buys. The
123
+ governance agent validates budget authority, brand safety, and compliance
124
+ independently of both the buyer and seller.
125
+
126
+ This step is optional but strongly recommended. Platforms that support governance
127
+ will call the registered agent during create_media_buy to validate the buy before
128
+ confirming it.
129
+
130
+ steps:
131
+ - id: sync_governance
132
+ title: 'Register governance agents'
133
+ narrative: |
134
+ The buyer tells your platform: "Before you confirm any media buy for this
135
+ account, call this governance agent to validate it." Your platform stores
136
+ the governance agent URL and will call it during create_media_buy.
137
+
138
+ This uses replace semantics — each sync_governance call replaces any
139
+ previously registered agents for the account.
140
+ task: sync_governance
141
+ schema_ref: 'account/sync-governance-request.json'
142
+ response_schema_ref: 'account/sync-governance-response.json'
143
+ doc_ref: '/accounts/tasks/sync_governance'
144
+ comply_scenario: governance_setup
145
+ stateful: true
146
+ expected: |
147
+ Acknowledge the governance agents. Your platform should:
148
+ - Store the governance agent URLs for the specified accounts
149
+ - Return confirmation that agents were registered
150
+ - Use these agents during create_media_buy validation
151
+
152
+ sample_request:
153
+ accounts:
154
+ - account:
155
+ brand:
156
+ domain: 'acmeoutdoor.com'
157
+ operator: 'pinnacle-agency.com'
158
+ governance_agents:
159
+ - url: 'https://governance.pinnacle-agency.example'
160
+ authentication:
161
+ schemes: ['Bearer']
162
+ credentials: 'gov-token-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
163
+ categories: ['budget_authority', 'brand_policy']
164
+
165
+ validations:
166
+ - check: response_schema
167
+ description: 'Response matches sync-governance-response.json schema'
168
+
169
+ - id: product_discovery
170
+ title: 'Product discovery'
171
+ narrative: |
172
+ The buyer sends a natural-language brief describing what they want to buy.
173
+ Your platform interprets the brief against your inventory and returns products —
174
+ structured representations of what you can sell, with pricing, delivery forecasts,
175
+ targeting options, and creative requirements.
176
+
177
+ This is where seller differentiation happens. The same brief sent to three sellers
178
+ produces three different product sets. Your AI interprets "premium video on sports
179
+ and outdoor lifestyle" against your specific inventory, audiences, and pricing.
180
+
181
+ steps:
182
+ - id: get_products_brief
183
+ title: 'Send a brief'
184
+ narrative: |
185
+ The buyer describes what they want in natural language. Your platform returns
186
+ products that match the brief, including pricing options, delivery forecasts,
187
+ and creative format requirements.
188
+
189
+ This call may take up to 60 seconds — your platform is running AI inference
190
+ against your inventory catalog. If the brief is ambiguous, you can return
191
+ input-required to ask clarifying questions before producing results.
192
+ task: get_products
193
+ schema_ref: 'media-buy/get-products-request.json'
194
+ response_schema_ref: 'media-buy/get-products-response.json'
195
+ doc_ref: '/media-buy/task-reference/get_products'
196
+ comply_scenario: media_buy_flow
197
+ stateful: false
198
+ expected: |
199
+ Return products matching the brief. Each product should include:
200
+ - product_id: unique identifier
201
+ - name and description
202
+ - delivery_type: guaranteed or non_guaranteed
203
+ - pricing_models: available pricing options (CPM, CPC, etc.)
204
+ - forecast: estimated impressions, reach
205
+ - creative_format_ids: what creative formats this product requires
206
+ - targeting: what audiences or contexts this product reaches
207
+
208
+ Optionally return proposals — curated media plans that bundle products
209
+ with budget allocations the buyer can accept or refine.
210
+
211
+ If the brief is unclear, return input-required with clarifying questions.
212
+
213
+ sample_request:
214
+ buying_mode: 'brief'
215
+ brief: 'Premium video inventory on sports and outdoor lifestyle publishers. Q2 flight, $50K budget. Adults 25-54, US and Canada.'
216
+ brand:
217
+ domain: 'acmeoutdoor.com'
218
+ account:
219
+ brand:
220
+ domain: 'acmeoutdoor.com'
221
+ operator: 'pinnacle-agency.com'
222
+
223
+ validations:
224
+ - check: response_schema
225
+ description: 'Response matches get-products-response.json schema'
226
+ - check: field_present
227
+ path: 'products'
228
+ description: 'Response contains a products array'
229
+ - check: field_present
230
+ path: 'products[0].product_id'
231
+ description: 'Each product has a product_id'
232
+ - check: field_present
233
+ path: 'products[0].delivery_type'
234
+ description: 'Each product declares guaranteed or non_guaranteed delivery'
235
+
236
+ - id: proposal_refinement
237
+ title: 'Proposal refinement'
238
+ narrative: |
239
+ The buyer reviews the products from the brief and wants to narrow down. They
240
+ switch to refine mode, layering constraints without starting over. Each refinement
241
+ narrows the previous result set.
242
+
243
+ This is iterative negotiation. The buyer might say "only guaranteed packages" or
244
+ "increase the CTV allocation to 60%" or "drop the audio product and redistribute
245
+ that budget." Your platform adjusts the products and proposals accordingly.
246
+
247
+ steps:
248
+ - id: get_products_refine
249
+ title: 'Refine the proposal'
250
+ narrative: |
251
+ The buyer has reviewed the initial products and wants adjustments. They call
252
+ get_products with buying_mode: refine and a refine array describing what to
253
+ change. Your platform applies the refinements and returns updated products.
254
+ task: get_products
255
+ schema_ref: 'media-buy/get-products-request.json'
256
+ response_schema_ref: 'media-buy/get-products-response.json'
257
+ doc_ref: '/media-buy/task-reference/get_products'
258
+ comply_scenario: media_buy_flow
259
+ stateful: true
260
+ expected: |
261
+ Return updated products reflecting the refinements. The response should:
262
+ - Apply each refinement to the relevant scope (request, product, or proposal)
263
+ - Include refinement_applied showing how each request was handled
264
+ - Preserve products that weren't targeted by refinements
265
+ - Update pricing and forecasts to reflect the changes
266
+
267
+ sample_request:
268
+ buying_mode: 'refine'
269
+ refine:
270
+ - scope: 'request'
271
+ ask: 'Only guaranteed packages. Must include completion rate SLA above 80%.'
272
+ - scope: 'product'
273
+ product_id: 'sports_preroll_q2'
274
+ ask: 'Increase budget allocation to $30K'
275
+ brand:
276
+ domain: 'acmeoutdoor.com'
277
+ account:
278
+ brand:
279
+ domain: 'acmeoutdoor.com'
280
+ operator: 'pinnacle-agency.com'
281
+
282
+ validations:
283
+ - check: response_schema
284
+ description: 'Response matches get-products-response.json schema'
285
+ - check: field_present
286
+ path: 'products'
287
+ description: 'Response contains updated products'
288
+
289
+ - id: create_buy
290
+ title: 'Create the media buy'
291
+ narrative: |
292
+ The buyer is satisfied with the products and creates a media buy. This is the
293
+ equivalent of signing an IO — the buyer commits to specific products, budgets,
294
+ and flight dates.
295
+
296
+ This operation may be synchronous (completed immediately), asynchronous (working
297
+ or submitted while your platform processes), or require human approval
298
+ (pending_approval with a URL for the human to sign off).
299
+
300
+ If the buyer registered governance agents in Phase 2, your platform calls
301
+ check_governance before confirming the buy. The governance agent validates budget
302
+ authority, brand safety, and compliance. If governance denies the buy, return the
303
+ denial — don't override it.
304
+
305
+ steps:
306
+ - id: create_media_buy
307
+ title: 'Create a media buy'
308
+ narrative: |
309
+ The buyer commits to specific products with budgets and flight dates. Your
310
+ platform validates the request, optionally calls governance, and either confirms
311
+ the buy or sends it through an approval workflow.
312
+
313
+ Two creation modes:
314
+ - Manual: buyer specifies packages array with explicit product selections
315
+ - Proposal: buyer passes a proposal_id from get_products to execute a proposal
316
+
317
+ The response status tells the buyer what happens next:
318
+ - completed: buy is confirmed and live
319
+ - working: your platform is processing (poll or wait for webhook)
320
+ - submitted: long-running async — approval workflow, IO signing, etc.
321
+ - input-required: need more information (budget clarification, approval)
322
+ task: create_media_buy
323
+ schema_ref: 'media-buy/create-media-buy-request.json'
324
+ response_schema_ref: 'media-buy/create-media-buy-response.json'
325
+ doc_ref: '/media-buy/task-reference/create_media_buy'
326
+ comply_scenario: media_buy_flow
327
+ stateful: true
328
+ expected: |
329
+ Process the media buy request and return one of:
330
+
331
+ Synchronous (completed):
332
+ - media_buy_id: your platform's identifier
333
+ - status: confirmed or pending_creatives
334
+ - packages: confirmed line items with pricing
335
+ - confirmed_at: timestamp
336
+ - valid_actions: what the buyer can do next
337
+
338
+ Asynchronous (working):
339
+ - percentage: 0-100 completion
340
+ - current_step: what's happening ("Validating inventory", "Checking governance")
341
+
342
+ Async with human approval (submitted):
343
+ - estimated_completion: when the buyer should expect a result
344
+ - The buyer configures push_notification_config to receive a webhook when done
345
+
346
+ Needs input (input-required):
347
+ - reason: APPROVAL_REQUIRED, BUDGET_EXCEEDS_LIMIT, CLARIFICATION_NEEDED
348
+ - errors: what needs to be resolved
349
+ - setup URL for human to complete approval (IO signing, budget authorization)
350
+
351
+ sample_request:
352
+ account:
353
+ brand:
354
+ domain: 'acmeoutdoor.com'
355
+ operator: 'pinnacle-agency.com'
356
+ brand:
357
+ domain: 'acmeoutdoor.com'
358
+ start_time: '2026-04-01T00:00:00Z'
359
+ end_time: '2026-06-30T23:59:59Z'
360
+ packages:
361
+ - product_id: 'sports_preroll_q2'
362
+ budget: 25000
363
+ pricing_option_id: 'cpm_guaranteed'
364
+ creative_assignments:
365
+ - creative_id: 'video_30s_trail_pro'
366
+ - product_id: 'lifestyle_display_q2'
367
+ budget: 15000
368
+ pricing_option_id: 'cpm_standard'
369
+ push_notification_config:
370
+ url: 'https://buyer.example/webhooks/adcp'
371
+ authentication:
372
+ scheme: 'HMAC-SHA256'
373
+
374
+ validations:
375
+ - check: response_schema
376
+ description: 'Response matches create-media-buy-response.json schema'
377
+
378
+ - id: check_buy_status
379
+ title: 'Check media buy status'
380
+ narrative: |
381
+ If create_media_buy returned working or submitted, the buyer polls for status
382
+ updates. Your platform returns the current state of the media buy — whether
383
+ it's still processing, awaiting approval, or confirmed.
384
+
385
+ This is also how the buyer checks for pending_approval status. If your platform
386
+ requires IO signing or human authorization, the buy sits at pending_approval
387
+ until the human completes the action. Your platform sends back a URL where the
388
+ human goes to approve.
389
+ task: get_media_buys
390
+ schema_ref: 'media-buy/get-media-buys-request.json'
391
+ response_schema_ref: 'media-buy/get-media-buys-response.json'
392
+ doc_ref: '/media-buy/task-reference/get_media_buys'
393
+ comply_scenario: media_buy_flow
394
+ stateful: true
395
+ expected: |
396
+ Return the current state of the media buy:
397
+ - media_buy_id: matches what was returned from create_media_buy
398
+ - status: draft, pending_approval, confirmed, active, paused, completed, canceled
399
+ - packages: line items with current delivery status
400
+ - valid_actions: what operations are available in this state
401
+
402
+ If pending_approval:
403
+ - Include setup URL where the human completes approval
404
+ - Include message explaining what's needed
405
+
406
+ sample_request:
407
+ account:
408
+ brand:
409
+ domain: 'acmeoutdoor.com'
410
+ operator: 'pinnacle-agency.com'
411
+ media_buy_ids:
412
+ - 'mb_acme_q2_2026'
413
+
414
+ validations:
415
+ - check: response_schema
416
+ description: 'Response matches get-media-buys-response.json schema'
417
+ - check: field_present
418
+ path: 'media_buys[0].status'
419
+ description: 'Each media buy has a status'
420
+
421
+ - id: creative_sync
422
+ title: 'Creative sync'
423
+ narrative: |
424
+ With the media buy confirmed, the buyer syncs creative assets to your platform.
425
+ Each package in the buy has creative format requirements — the buyer discovered
426
+ these during product discovery and now pushes matching assets.
427
+
428
+ Your platform validates each creative against the format specs and returns
429
+ per-creative status. If assets need review or transcoding, the operation may
430
+ go async.
431
+
432
+ steps:
433
+ - id: list_formats
434
+ title: 'Check creative format requirements'
435
+ narrative: |
436
+ The buyer confirms what creative formats the confirmed packages require.
437
+ Your platform returns format specs with asset requirements, dimensions,
438
+ and constraints.
439
+ task: list_creative_formats
440
+ schema_ref: 'creative/list-creative-formats-request.json'
441
+ response_schema_ref: 'creative/list-creative-formats-response.json'
442
+ doc_ref: '/creative/task-reference/list_creative_formats'
443
+ comply_scenario: creative_sync
444
+ stateful: false
445
+ expected: |
446
+ Return creative formats your platform accepts. Each format should define:
447
+ - format_id with your agent_url and unique id
448
+ - Asset requirements (dimensions, file sizes, mime types)
449
+ - Render dimensions
450
+
451
+ sample_request: {}
452
+
453
+ validations:
454
+ - check: response_schema
455
+ description: 'Response matches list-creative-formats-response.json schema'
456
+ - check: field_present
457
+ path: 'formats'
458
+ description: 'Response contains formats array'
459
+
460
+ - id: sync_creatives
461
+ title: 'Push creative assets'
462
+ narrative: |
463
+ The buyer uploads creative assets for the confirmed packages. Your platform
464
+ validates each creative against the format specs, transcodes if necessary,
465
+ and returns per-creative status.
466
+ task: sync_creatives
467
+ schema_ref: 'creative/sync-creatives-request.json'
468
+ response_schema_ref: 'creative/sync-creatives-response.json'
469
+ doc_ref: '/creative/task-reference/sync_creatives'
470
+ comply_scenario: creative_sync
471
+ stateful: true
472
+ expected: |
473
+ Accept and validate creatives:
474
+ - Per-creative action: created or updated
475
+ - Per-creative status: accepted, pending_review, or rejected
476
+ - Validation errors for rejected creatives
477
+ - Platform-assigned IDs if applicable
478
+
479
+ sample_request:
480
+ account:
481
+ brand:
482
+ domain: 'acmeoutdoor.com'
483
+ operator: 'pinnacle-agency.com'
484
+ creatives:
485
+ - creative_id: 'video_30s_trail_pro'
486
+ name: 'Trail Pro 3000 - 30s CTV Spot'
487
+ format_id:
488
+ agent_url: 'https://your-platform.example.com'
489
+ id: 'ssai_30s'
490
+ assets:
491
+ - asset_id: 'video'
492
+ asset_type: 'video'
493
+ url: 'https://cdn.pinnacle-agency.example/trail-pro-30s.mp4'
494
+ mime_type: 'video/mp4'
495
+ - creative_id: 'display_trail_pro_300x250'
496
+ name: 'Trail Pro 3000 - Display 300x250'
497
+ format_id:
498
+ agent_url: 'https://your-platform.example.com'
499
+ id: 'display_300x250'
500
+ assets:
501
+ - asset_id: 'image'
502
+ asset_type: 'image'
503
+ url: 'https://cdn.pinnacle-agency.example/trail-pro-300x250.png'
504
+ mime_type: 'image/png'
505
+
506
+ validations:
507
+ - check: response_schema
508
+ description: 'Response matches sync-creatives-response.json schema'
509
+ - check: field_present
510
+ path: 'creatives[0].action'
511
+ description: 'Each creative has an action (created/updated)'
512
+
513
+ - id: delivery_monitoring
514
+ title: 'Delivery and reporting'
515
+ narrative: |
516
+ The campaign is live. The buyer monitors delivery through two tasks:
517
+ get_media_buys for status and get_media_buy_delivery for performance metrics.
518
+
519
+ Your platform reports in a standard format — impressions, clicks, spend,
520
+ completion rates — so the buyer can compare delivery across multiple sellers
521
+ in a single view.
522
+
523
+ steps:
524
+ - id: get_delivery
525
+ title: 'Check delivery metrics'
526
+ narrative: |
527
+ The buyer requests delivery data for the active media buy. Your platform
528
+ returns performance metrics — impressions, clicks, spend, completion rates —
529
+ broken down by package and optionally by day.
530
+
531
+ This call may take up to 60 seconds as your platform aggregates reporting
532
+ data across delivery systems.
533
+ task: get_media_buy_delivery
534
+ schema_ref: 'media-buy/get-media-buy-delivery-request.json'
535
+ response_schema_ref: 'media-buy/get-media-buy-delivery-response.json'
536
+ doc_ref: '/media-buy/task-reference/get_media_buy_delivery'
537
+ comply_scenario: media_buy_flow
538
+ stateful: true
539
+ expected: |
540
+ Return delivery metrics for the media buy:
541
+ - Per-package delivery: impressions, clicks, spend, completion rates
542
+ - Daily breakdown if requested (include_package_daily_breakdown)
543
+ - Pacing information: on track, ahead, behind
544
+ - Budget utilization: spent vs. committed
545
+
546
+ sample_request:
547
+ account:
548
+ brand:
549
+ domain: 'acmeoutdoor.com'
550
+ operator: 'pinnacle-agency.com'
551
+ media_buy_ids:
552
+ - 'mb_acme_q2_2026'
553
+ include_package_daily_breakdown: true
554
+
555
+ validations:
556
+ - check: response_schema
557
+ description: 'Response matches get-media-buy-delivery-response.json schema'
558
+ - check: field_present
559
+ path: 'media_buy_deliveries'
560
+ description: 'Response contains media buy delivery data'