@adcp/client 4.21.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.
- package/AGENTS.md +278 -0
- package/README.md +96 -61
- package/bin/adcp.js +342 -4
- package/dist/lib/agents/index.generated.d.ts +9 -1
- package/dist/lib/agents/index.generated.d.ts.map +1 -1
- package/dist/lib/agents/index.generated.js +12 -0
- package/dist/lib/agents/index.generated.js.map +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts +2 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +10 -1
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/discovery/property-crawler.d.ts +4 -0
- package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
- package/dist/lib/discovery/property-crawler.js +10 -2
- package/dist/lib/discovery/property-crawler.js.map +1 -1
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +6 -4
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +8 -6
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/protocols/mcp.d.ts.map +1 -1
- package/dist/lib/protocols/mcp.js +24 -11
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +3 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/serve.d.ts +45 -0
- package/dist/lib/server/serve.d.ts.map +1 -0
- package/dist/lib/server/serve.js +86 -0
- package/dist/lib/server/serve.js.map +1 -0
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +1 -0
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +48 -63
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
- package/dist/lib/testing/compliance/types.d.ts +1 -1
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -0
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +23 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/orchestrator.d.ts +8 -0
- package/dist/lib/testing/orchestrator.d.ts.map +1 -1
- package/dist/lib/testing/orchestrator.js +8 -0
- package/dist/lib/testing/orchestrator.js.map +1 -1
- package/dist/lib/testing/storyboard/context.d.ts +34 -0
- package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/context.js +257 -0
- package/dist/lib/testing/storyboard/context.js.map +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +15 -0
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/index.js +48 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -0
- package/dist/lib/testing/storyboard/loader.d.ts +53 -0
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/loader.js +114 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -0
- package/dist/lib/testing/storyboard/path.d.ts +29 -0
- package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/path.js +121 -0
- package/dist/lib/testing/storyboard/path.js.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.js +410 -0
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
- package/dist/lib/testing/storyboard/runner.d.ts +24 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/runner.js +280 -0
- package/dist/lib/testing/storyboard/runner.js.map +1 -0
- package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/task-map.js +84 -0
- package/dist/lib/testing/storyboard/task-map.js.map +1 -0
- package/dist/lib/testing/storyboard/types.d.ts +156 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/types.js +10 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -0
- package/dist/lib/testing/storyboard/validations.d.ts +17 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/validations.js +166 -0
- package/dist/lib/testing/storyboard/validations.js.map +1 -0
- package/dist/lib/testing/types.d.ts +2 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/core.generated.d.ts +2 -2
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/schemas.generated.d.ts +193 -34
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +87 -5
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +280 -3
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +34 -3
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/utils/validate-user-agent.d.ts +8 -0
- package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
- package/dist/lib/utils/validate-user-agent.js +15 -0
- package/dist/lib/utils/validate-user-agent.js.map +1 -0
- package/dist/lib/version.d.ts +6 -0
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +7 -1
- package/dist/lib/version.js.map +1 -1
- package/docs/README.md +42 -0
- package/docs/guides/BUILD-AN-AGENT.md +292 -0
- package/docs/llms.txt +634 -0
- package/examples/README.md +106 -0
- package/examples/adcp.config.json +30 -0
- package/examples/basic-a2a.ts +76 -0
- package/examples/basic-mcp.ts +50 -0
- package/examples/batch-preview-test.ts +266 -0
- package/examples/conversation-client.ts +291 -0
- package/examples/debug-preview-response.ts +73 -0
- package/examples/debug-preview-with-logging.ts +50 -0
- package/examples/easy-config-demo.ts +242 -0
- package/examples/env-config.ts +51 -0
- package/examples/error-compliant-server.ts +237 -0
- package/examples/generative-creative-demo.ts +205 -0
- package/examples/inspect-card-formats.ts +161 -0
- package/examples/logger-usage.ts +165 -0
- package/examples/oauth-cli-example.ts +154 -0
- package/examples/pr78-async-patterns-demo.ts +247 -0
- package/examples/signals-agent.ts +162 -0
- package/examples/simple-getting-started.ts +225 -0
- package/examples/simple-protocol-demo.ts +75 -0
- package/examples/test-helpers-demo.ts +239 -0
- package/examples/zod-validation-example.ts +126 -0
- package/package.json +12 -2
- package/skills/adcp/SKILL.md +13 -2
- package/storyboards/audience_sync.yaml +199 -0
- package/storyboards/behavioral_analysis.yaml +244 -0
- package/storyboards/brand_rights.yaml +131 -0
- package/storyboards/creative_ad_server.yaml +171 -0
- package/storyboards/creative_sales_agent.yaml +169 -0
- package/storyboards/creative_template.yaml +306 -0
- package/storyboards/deterministic_testing.yaml +925 -0
- package/storyboards/error_compliance.yaml +231 -0
- package/storyboards/governance_content_standards.yaml +213 -0
- package/storyboards/governance_property_lists.yaml +372 -0
- package/storyboards/media_buy_catalog_creative.yaml +457 -0
- package/storyboards/media_buy_governance_escalation.yaml +467 -0
- package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
- package/storyboards/media_buy_non_guaranteed.yaml +288 -0
- package/storyboards/media_buy_proposal_mode.yaml +369 -0
- package/storyboards/media_buy_seller.yaml +560 -0
- package/storyboards/media_buy_state_machine.yaml +254 -0
- package/storyboards/schema.yaml +65 -0
- package/storyboards/schema_validation.yaml +166 -0
- package/storyboards/si_session.yaml +384 -0
- package/storyboards/signal_marketplace.yaml +283 -0
- package/storyboards/signal_owned.yaml +211 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
id: media_buy_guaranteed_approval
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Guaranteed media buy with human IO approval"
|
|
4
|
+
category: media_buy_guaranteed_approval
|
|
5
|
+
summary: "Seller agent that requires human-in-the-loop IO signing before guaranteed media buys go live."
|
|
6
|
+
platform_types:
|
|
7
|
+
- display_ad_server
|
|
8
|
+
- video_ad_server
|
|
9
|
+
- audio_platform
|
|
10
|
+
- linear_tv_platform
|
|
11
|
+
|
|
12
|
+
track: media_buy
|
|
13
|
+
required_tools:
|
|
14
|
+
- create_media_buy
|
|
15
|
+
narrative: |
|
|
16
|
+
You run a sell-side platform that requires human approval before guaranteed media buys go
|
|
17
|
+
live. When a buyer creates a guaranteed buy, your platform returns a submitted status with
|
|
18
|
+
an estimated completion time. A human reviewer on your side reviews the deal terms and
|
|
19
|
+
signs the IO through a URL your platform provides.
|
|
20
|
+
|
|
21
|
+
The buyer either polls get_media_buys or configures a push_notification_config webhook to
|
|
22
|
+
receive a callback when the IO is signed. Once approved, the media buy transitions from
|
|
23
|
+
pending_approval to confirmed/active and the buyer can sync creatives and monitor delivery.
|
|
24
|
+
|
|
25
|
+
This storyboard isolates the guaranteed approval path — the async handshake between agent
|
|
26
|
+
automation and human decision-making that makes guaranteed buys work in practice.
|
|
27
|
+
|
|
28
|
+
agent:
|
|
29
|
+
interaction_model: media_buy_seller
|
|
30
|
+
capabilities:
|
|
31
|
+
- sells_media
|
|
32
|
+
- supports_guaranteed
|
|
33
|
+
- requires_io_approval
|
|
34
|
+
examples:
|
|
35
|
+
- "Premium publisher with IO requirements"
|
|
36
|
+
- "Retail media network with sales approval"
|
|
37
|
+
- "CTV platform with guaranteed deals"
|
|
38
|
+
|
|
39
|
+
caller:
|
|
40
|
+
role: buyer_agent
|
|
41
|
+
example: "Scope3 (DSP)"
|
|
42
|
+
|
|
43
|
+
prerequisites:
|
|
44
|
+
description: |
|
|
45
|
+
The caller needs a brand identity and operator credentials for account setup.
|
|
46
|
+
The test kit provides a sample brand (Acme Outdoor) with campaign parameters
|
|
47
|
+
suitable for testing the guaranteed approval flow.
|
|
48
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
49
|
+
|
|
50
|
+
phases:
|
|
51
|
+
- id: account_setup
|
|
52
|
+
title: "Account setup"
|
|
53
|
+
narrative: |
|
|
54
|
+
Before buying anything, the buyer establishes an account relationship with
|
|
55
|
+
your platform. This is the handshake: the buyer tells you which brand and
|
|
56
|
+
agency (operator) they represent, and you return an account ID, status, and
|
|
57
|
+
any setup requirements.
|
|
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. This is
|
|
64
|
+
the first call in any new relationship. Your platform validates the request,
|
|
65
|
+
provisions the account, and returns its status.
|
|
66
|
+
task: sync_accounts
|
|
67
|
+
schema_ref: "account/sync-accounts-request.json"
|
|
68
|
+
response_schema_ref: "account/sync-accounts-response.json"
|
|
69
|
+
doc_ref: "/accounts/tasks/sync_accounts"
|
|
70
|
+
stateful: true
|
|
71
|
+
expected: |
|
|
72
|
+
Return the account with:
|
|
73
|
+
- account_id: your platform's identifier for this relationship
|
|
74
|
+
- action: created or updated
|
|
75
|
+
- status: active or pending_approval
|
|
76
|
+
- account_scope: operator, brand, operator_brand, or agent
|
|
77
|
+
- setup: URL and message if pending_approval
|
|
78
|
+
- payment_terms: net_30, prepay, etc.
|
|
79
|
+
|
|
80
|
+
sample_request:
|
|
81
|
+
accounts:
|
|
82
|
+
- brand:
|
|
83
|
+
domain: "acmeoutdoor.com"
|
|
84
|
+
operator: "pinnacle-agency.com"
|
|
85
|
+
billing: "operator"
|
|
86
|
+
payment_terms: "net_30"
|
|
87
|
+
|
|
88
|
+
validations:
|
|
89
|
+
- check: response_schema
|
|
90
|
+
description: "Response matches sync-accounts-response.json schema"
|
|
91
|
+
- check: field_present
|
|
92
|
+
path: "accounts[0].account_id"
|
|
93
|
+
description: "Account has a platform-assigned ID"
|
|
94
|
+
- check: field_present
|
|
95
|
+
path: "accounts[0].status"
|
|
96
|
+
description: "Account has a status (active or pending_approval)"
|
|
97
|
+
|
|
98
|
+
- id: product_discovery
|
|
99
|
+
title: "Discover guaranteed products"
|
|
100
|
+
narrative: |
|
|
101
|
+
The buyer sends a brief to discover your guaranteed inventory. The emphasis
|
|
102
|
+
here is on products with delivery_type: guaranteed — fixed-price, reserved
|
|
103
|
+
inventory that requires an IO commitment. Your platform returns products with
|
|
104
|
+
pricing, delivery forecasts, and SLA commitments.
|
|
105
|
+
|
|
106
|
+
steps:
|
|
107
|
+
- id: get_products_brief
|
|
108
|
+
title: "Send a brief targeting guaranteed inventory"
|
|
109
|
+
narrative: |
|
|
110
|
+
The buyer describes what they want, emphasizing guaranteed delivery. Your
|
|
111
|
+
platform returns products with delivery_type: guaranteed, including SLA
|
|
112
|
+
commitments, minimum spend requirements, and IO terms.
|
|
113
|
+
task: get_products
|
|
114
|
+
schema_ref: "media-buy/get-products-request.json"
|
|
115
|
+
response_schema_ref: "media-buy/get-products-response.json"
|
|
116
|
+
doc_ref: "/media-buy/task-reference/get_products"
|
|
117
|
+
stateful: false
|
|
118
|
+
expected: |
|
|
119
|
+
Return guaranteed products matching the brief. Each product should include:
|
|
120
|
+
- product_id: unique identifier
|
|
121
|
+
- name and description
|
|
122
|
+
- delivery_type: guaranteed
|
|
123
|
+
- pricing_models: fixed CPM or flat-rate pricing
|
|
124
|
+
- forecast: committed impressions with SLA guarantees
|
|
125
|
+
- creative_format_ids: required creative formats
|
|
126
|
+
- minimum_spend or commitment terms if applicable
|
|
127
|
+
|
|
128
|
+
sample_request:
|
|
129
|
+
buying_mode: "brief"
|
|
130
|
+
brief: "Guaranteed premium video on sports and outdoor lifestyle publishers. Q2 flight, $50K budget. Adults 25-54, US only. Need completion rate SLA."
|
|
131
|
+
brand:
|
|
132
|
+
domain: "acmeoutdoor.com"
|
|
133
|
+
account:
|
|
134
|
+
brand:
|
|
135
|
+
domain: "acmeoutdoor.com"
|
|
136
|
+
operator: "pinnacle-agency.com"
|
|
137
|
+
|
|
138
|
+
validations:
|
|
139
|
+
- check: response_schema
|
|
140
|
+
description: "Response matches get-products-response.json schema"
|
|
141
|
+
- check: field_present
|
|
142
|
+
path: "products"
|
|
143
|
+
description: "Response contains a products array"
|
|
144
|
+
- check: field_present
|
|
145
|
+
path: "products[0].product_id"
|
|
146
|
+
description: "Each product has a product_id"
|
|
147
|
+
- check: field_present
|
|
148
|
+
path: "products[0].delivery_type"
|
|
149
|
+
description: "Each product declares delivery_type: guaranteed"
|
|
150
|
+
|
|
151
|
+
- id: create_buy_submitted
|
|
152
|
+
title: "Create guaranteed buy (submitted for approval)"
|
|
153
|
+
narrative: |
|
|
154
|
+
The buyer creates a guaranteed media buy. Because your platform requires human
|
|
155
|
+
IO signing for guaranteed deals, the response comes back as submitted — not
|
|
156
|
+
completed. The buyer gets an estimated_completion timestamp indicating when the
|
|
157
|
+
IO review should finish. The buyer configures a webhook to be notified when the
|
|
158
|
+
status changes.
|
|
159
|
+
|
|
160
|
+
steps:
|
|
161
|
+
- id: create_media_buy
|
|
162
|
+
title: "Create a guaranteed media buy"
|
|
163
|
+
narrative: |
|
|
164
|
+
The buyer commits to guaranteed products with budgets and flight dates. Your
|
|
165
|
+
platform accepts the request but does not confirm it immediately. Instead,
|
|
166
|
+
it enters an IO approval workflow and returns submitted status with an
|
|
167
|
+
estimated_completion timestamp.
|
|
168
|
+
|
|
169
|
+
The buyer includes push_notification_config so your platform can call back
|
|
170
|
+
when the IO is signed (or rejected).
|
|
171
|
+
task: create_media_buy
|
|
172
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
173
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
174
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
175
|
+
stateful: true
|
|
176
|
+
expected: |
|
|
177
|
+
Return the media buy in submitted status:
|
|
178
|
+
- media_buy_id: your platform's identifier
|
|
179
|
+
- status: submitted (NOT completed — this requires human approval)
|
|
180
|
+
- estimated_completion: timestamp when the IO review should finish
|
|
181
|
+
- packages: the proposed line items echoed back
|
|
182
|
+
- The buyer's push_notification_config is acknowledged
|
|
183
|
+
|
|
184
|
+
Do NOT return completed status for guaranteed buys that require IO signing.
|
|
185
|
+
|
|
186
|
+
sample_request:
|
|
187
|
+
account:
|
|
188
|
+
brand:
|
|
189
|
+
domain: "acmeoutdoor.com"
|
|
190
|
+
operator: "pinnacle-agency.com"
|
|
191
|
+
brand:
|
|
192
|
+
domain: "acmeoutdoor.com"
|
|
193
|
+
start_time: "2026-04-01T00:00:00Z"
|
|
194
|
+
end_time: "2026-06-30T23:59:59Z"
|
|
195
|
+
packages:
|
|
196
|
+
- product_id: "sports_preroll_q2_guaranteed"
|
|
197
|
+
budget: 30000
|
|
198
|
+
pricing_option_id: "cpm_guaranteed_fixed"
|
|
199
|
+
creative_assignments:
|
|
200
|
+
- creative_id: "video_30s_trail_pro"
|
|
201
|
+
- product_id: "outdoor_ctv_q2_guaranteed"
|
|
202
|
+
budget: 20000
|
|
203
|
+
pricing_option_id: "cpm_guaranteed_fixed"
|
|
204
|
+
push_notification_config:
|
|
205
|
+
url: "https://buyer.example/webhooks/adcp"
|
|
206
|
+
authentication:
|
|
207
|
+
scheme: "HMAC-SHA256"
|
|
208
|
+
|
|
209
|
+
validations:
|
|
210
|
+
- check: response_schema
|
|
211
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
212
|
+
|
|
213
|
+
- id: poll_approval
|
|
214
|
+
title: "Poll for IO approval"
|
|
215
|
+
narrative: |
|
|
216
|
+
The media buy is sitting in an approval queue. A human on the seller side needs
|
|
217
|
+
to review the deal terms and sign the IO. The buyer polls get_media_buys to check
|
|
218
|
+
the current status. Your platform returns pending_approval with a setup URL where
|
|
219
|
+
the human reviewer signs the IO and a message explaining what is needed.
|
|
220
|
+
|
|
221
|
+
steps:
|
|
222
|
+
- id: get_media_buys_pending
|
|
223
|
+
title: "Check media buy status (pending approval)"
|
|
224
|
+
narrative: |
|
|
225
|
+
The buyer polls for the media buy status. Your platform returns
|
|
226
|
+
pending_approval with a setup object containing the URL where the human
|
|
227
|
+
reviewer signs the IO and a message describing what action is needed.
|
|
228
|
+
task: get_media_buys
|
|
229
|
+
schema_ref: "media-buy/get-media-buys-request.json"
|
|
230
|
+
response_schema_ref: "media-buy/get-media-buys-response.json"
|
|
231
|
+
doc_ref: "/media-buy/task-reference/get_media_buys"
|
|
232
|
+
stateful: true
|
|
233
|
+
expected: |
|
|
234
|
+
Return the media buy in pending_approval status:
|
|
235
|
+
- media_buy_id: matches the buy created earlier
|
|
236
|
+
- status: pending_approval
|
|
237
|
+
- setup.url: where the human goes to review and sign the IO
|
|
238
|
+
- setup.message: explains what the human needs to do (e.g., "Review and sign the IO for Acme Outdoor Q2 campaign")
|
|
239
|
+
- packages: line items with their current state
|
|
240
|
+
- valid_actions: what the buyer can do in this state
|
|
241
|
+
|
|
242
|
+
sample_request:
|
|
243
|
+
account:
|
|
244
|
+
brand:
|
|
245
|
+
domain: "acmeoutdoor.com"
|
|
246
|
+
operator: "pinnacle-agency.com"
|
|
247
|
+
media_buy_ids:
|
|
248
|
+
- "mb_acme_q2_2026_guaranteed"
|
|
249
|
+
|
|
250
|
+
validations:
|
|
251
|
+
- check: response_schema
|
|
252
|
+
description: "Response matches get-media-buys-response.json schema"
|
|
253
|
+
- check: field_present
|
|
254
|
+
path: "media_buys[0].status"
|
|
255
|
+
description: "Media buy has a status"
|
|
256
|
+
- check: field_present
|
|
257
|
+
path: "media_buys[0].setup.url"
|
|
258
|
+
description: "Pending approval buy includes a setup URL for IO signing"
|
|
259
|
+
- check: field_present
|
|
260
|
+
path: "media_buys[0].setup.message"
|
|
261
|
+
description: "Pending approval buy includes a message explaining what's needed"
|
|
262
|
+
|
|
263
|
+
- id: confirm_active
|
|
264
|
+
title: "Confirm active after IO signing"
|
|
265
|
+
narrative: |
|
|
266
|
+
The human has reviewed the IO and signed it through the setup URL. The buyer
|
|
267
|
+
polls get_media_buys again (or received a webhook notification) and sees that the
|
|
268
|
+
media buy has transitioned from pending_approval to confirmed or active. The buy
|
|
269
|
+
is now live.
|
|
270
|
+
|
|
271
|
+
steps:
|
|
272
|
+
- id: get_media_buys_confirmed
|
|
273
|
+
title: "Check media buy status (confirmed/active)"
|
|
274
|
+
narrative: |
|
|
275
|
+
After the human signs the IO, the buyer checks the media buy status again.
|
|
276
|
+
Your platform returns confirmed or active, indicating the buy is approved
|
|
277
|
+
and inventory is reserved.
|
|
278
|
+
task: get_media_buys
|
|
279
|
+
schema_ref: "media-buy/get-media-buys-request.json"
|
|
280
|
+
response_schema_ref: "media-buy/get-media-buys-response.json"
|
|
281
|
+
doc_ref: "/media-buy/task-reference/get_media_buys"
|
|
282
|
+
stateful: true
|
|
283
|
+
expected: |
|
|
284
|
+
Return the media buy in confirmed or active status:
|
|
285
|
+
- media_buy_id: matches the buy created earlier
|
|
286
|
+
- status: confirmed or active (IO has been signed)
|
|
287
|
+
- confirmed_at: timestamp when the IO was signed
|
|
288
|
+
- packages: line items now confirmed with reserved inventory
|
|
289
|
+
- valid_actions: updated for confirmed state (creative sync, pause, etc.)
|
|
290
|
+
|
|
291
|
+
sample_request:
|
|
292
|
+
account:
|
|
293
|
+
brand:
|
|
294
|
+
domain: "acmeoutdoor.com"
|
|
295
|
+
operator: "pinnacle-agency.com"
|
|
296
|
+
media_buy_ids:
|
|
297
|
+
- "mb_acme_q2_2026_guaranteed"
|
|
298
|
+
|
|
299
|
+
validations:
|
|
300
|
+
- check: response_schema
|
|
301
|
+
description: "Response matches get-media-buys-response.json schema"
|
|
302
|
+
- check: field_present
|
|
303
|
+
path: "media_buys[0].status"
|
|
304
|
+
description: "Media buy status is confirmed or active"
|
|
305
|
+
- check: field_present
|
|
306
|
+
path: "media_buys[0].confirmed_at"
|
|
307
|
+
description: "Confirmed buy includes a confirmed_at timestamp"
|
|
308
|
+
|
|
309
|
+
- id: creative_sync
|
|
310
|
+
title: "Creative sync"
|
|
311
|
+
narrative: |
|
|
312
|
+
With the IO signed and the media buy confirmed, the buyer syncs creative assets
|
|
313
|
+
to your platform. Each package has creative format requirements that the buyer
|
|
314
|
+
discovered during product discovery.
|
|
315
|
+
|
|
316
|
+
steps:
|
|
317
|
+
- id: sync_creatives
|
|
318
|
+
title: "Push creative assets"
|
|
319
|
+
narrative: |
|
|
320
|
+
The buyer uploads creative assets for the confirmed packages. Your platform
|
|
321
|
+
validates each creative against the format specs and returns per-creative status.
|
|
322
|
+
task: sync_creatives
|
|
323
|
+
schema_ref: "creative/sync-creatives-request.json"
|
|
324
|
+
response_schema_ref: "creative/sync-creatives-response.json"
|
|
325
|
+
doc_ref: "/creative/task-reference/sync_creatives"
|
|
326
|
+
stateful: true
|
|
327
|
+
expected: |
|
|
328
|
+
Accept and validate creatives:
|
|
329
|
+
- Per-creative action: created or updated
|
|
330
|
+
- Per-creative status: accepted, pending_review, or rejected
|
|
331
|
+
- Validation errors for rejected creatives
|
|
332
|
+
|
|
333
|
+
sample_request:
|
|
334
|
+
account:
|
|
335
|
+
brand:
|
|
336
|
+
domain: "acmeoutdoor.com"
|
|
337
|
+
operator: "pinnacle-agency.com"
|
|
338
|
+
creatives:
|
|
339
|
+
- creative_id: "video_30s_trail_pro"
|
|
340
|
+
name: "Trail Pro 3000 - 30s CTV Spot"
|
|
341
|
+
format_id:
|
|
342
|
+
agent_url: "https://your-platform.example.com"
|
|
343
|
+
id: "ssai_30s"
|
|
344
|
+
assets:
|
|
345
|
+
- asset_id: "video"
|
|
346
|
+
asset_type: "video"
|
|
347
|
+
url: "https://cdn.pinnacle-agency.example/trail-pro-30s.mp4"
|
|
348
|
+
mime_type: "video/mp4"
|
|
349
|
+
|
|
350
|
+
validations:
|
|
351
|
+
- check: response_schema
|
|
352
|
+
description: "Response matches sync-creatives-response.json schema"
|
|
353
|
+
- check: field_present
|
|
354
|
+
path: "creatives[0].action"
|
|
355
|
+
description: "Each creative has an action (created/updated)"
|
|
356
|
+
|
|
357
|
+
- id: delivery_monitoring
|
|
358
|
+
title: "Delivery and reporting"
|
|
359
|
+
narrative: |
|
|
360
|
+
The campaign is live with guaranteed delivery commitments. The buyer monitors
|
|
361
|
+
delivery to ensure the seller is meeting the SLA guarantees from the IO.
|
|
362
|
+
|
|
363
|
+
steps:
|
|
364
|
+
- id: get_delivery
|
|
365
|
+
title: "Check delivery metrics"
|
|
366
|
+
narrative: |
|
|
367
|
+
The buyer requests delivery data for the active guaranteed media buy. Your
|
|
368
|
+
platform returns performance metrics with pacing against the guaranteed
|
|
369
|
+
commitment.
|
|
370
|
+
task: get_media_buy_delivery
|
|
371
|
+
schema_ref: "media-buy/get-media-buy-delivery-request.json"
|
|
372
|
+
response_schema_ref: "media-buy/get-media-buy-delivery-response.json"
|
|
373
|
+
doc_ref: "/media-buy/task-reference/get_media_buy_delivery"
|
|
374
|
+
stateful: true
|
|
375
|
+
expected: |
|
|
376
|
+
Return delivery metrics for the guaranteed media buy:
|
|
377
|
+
- Per-package delivery: impressions, clicks, spend, completion rates
|
|
378
|
+
- Pacing against guaranteed commitment: on track, ahead, behind
|
|
379
|
+
- Budget utilization: spent vs. committed
|
|
380
|
+
- SLA compliance: completion rate vs. guaranteed threshold
|
|
381
|
+
|
|
382
|
+
sample_request:
|
|
383
|
+
account:
|
|
384
|
+
brand:
|
|
385
|
+
domain: "acmeoutdoor.com"
|
|
386
|
+
operator: "pinnacle-agency.com"
|
|
387
|
+
media_buy_ids:
|
|
388
|
+
- "mb_acme_q2_2026_guaranteed"
|
|
389
|
+
include_package_daily_breakdown: true
|
|
390
|
+
|
|
391
|
+
validations:
|
|
392
|
+
- check: response_schema
|
|
393
|
+
description: "Response matches get-media-buy-delivery-response.json schema"
|
|
394
|
+
- check: field_present
|
|
395
|
+
path: "media_buys"
|
|
396
|
+
description: "Response contains media buy delivery data"
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
id: media_buy_non_guaranteed
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Non-guaranteed auction-based media buy"
|
|
4
|
+
category: media_buy_non_guaranteed
|
|
5
|
+
summary: "Seller agent for auction-based, non-guaranteed buying where the buyer sets bid prices and budgets."
|
|
6
|
+
platform_types:
|
|
7
|
+
- social_platform
|
|
8
|
+
- dsp
|
|
9
|
+
- pmax_platform
|
|
10
|
+
- generative_dsp
|
|
11
|
+
|
|
12
|
+
track: media_buy
|
|
13
|
+
required_tools:
|
|
14
|
+
- create_media_buy
|
|
15
|
+
narrative: |
|
|
16
|
+
You run a sell-side platform with auction-based inventory. Non-guaranteed buys don't
|
|
17
|
+
require IOs or human approval — the buyer sets a bid price and budget, and your platform
|
|
18
|
+
runs the auction. Delivery is best-effort based on bid competitiveness.
|
|
19
|
+
|
|
20
|
+
The buyer discovers products with floor prices and bid guidance, creates a buy with bid
|
|
21
|
+
prices per package, monitors win rates and pacing, and adjusts bids or budgets in-flight
|
|
22
|
+
to optimize performance.
|
|
23
|
+
|
|
24
|
+
This storyboard covers the non-guaranteed buying path — fast setup, no human approval,
|
|
25
|
+
real-time optimization through bid and budget adjustments.
|
|
26
|
+
|
|
27
|
+
agent:
|
|
28
|
+
interaction_model: media_buy_seller
|
|
29
|
+
capabilities:
|
|
30
|
+
- sells_media
|
|
31
|
+
- supports_non_guaranteed
|
|
32
|
+
- auction_based
|
|
33
|
+
examples:
|
|
34
|
+
- "SSP with programmatic auction inventory"
|
|
35
|
+
- "Exchange-based publisher platform"
|
|
36
|
+
- "Open marketplace seller"
|
|
37
|
+
|
|
38
|
+
caller:
|
|
39
|
+
role: buyer_agent
|
|
40
|
+
example: "Scope3 (DSP)"
|
|
41
|
+
|
|
42
|
+
prerequisites:
|
|
43
|
+
description: |
|
|
44
|
+
The caller needs a brand identity and operator credentials. Non-guaranteed buys
|
|
45
|
+
typically have lower barriers to entry — no IO signing required. The test kit
|
|
46
|
+
provides a sample brand (Acme Outdoor) with bid parameters suitable for testing
|
|
47
|
+
the auction-based flow.
|
|
48
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
49
|
+
|
|
50
|
+
phases:
|
|
51
|
+
- id: product_discovery
|
|
52
|
+
title: "Discover auction-based products"
|
|
53
|
+
narrative: |
|
|
54
|
+
The buyer sends a brief to discover your non-guaranteed inventory. Products
|
|
55
|
+
come back with delivery_type: non_guaranteed, floor prices, and bid guidance
|
|
56
|
+
that helps the buyer set competitive bids.
|
|
57
|
+
|
|
58
|
+
steps:
|
|
59
|
+
- id: get_products_brief
|
|
60
|
+
title: "Send a brief for non-guaranteed inventory"
|
|
61
|
+
narrative: |
|
|
62
|
+
The buyer describes what they want. Your platform returns non-guaranteed
|
|
63
|
+
products with auction mechanics: floor prices, recommended bid ranges,
|
|
64
|
+
estimated win rates at different bid levels, and available audience segments.
|
|
65
|
+
task: get_products
|
|
66
|
+
schema_ref: "media-buy/get-products-request.json"
|
|
67
|
+
response_schema_ref: "media-buy/get-products-response.json"
|
|
68
|
+
doc_ref: "/media-buy/task-reference/get_products"
|
|
69
|
+
stateful: false
|
|
70
|
+
expected: |
|
|
71
|
+
Return non-guaranteed products matching the brief. Each product should include:
|
|
72
|
+
- product_id: unique identifier
|
|
73
|
+
- name and description
|
|
74
|
+
- delivery_type: non_guaranteed
|
|
75
|
+
- pricing_models: auction-based pricing with floor_price and recommended bid range
|
|
76
|
+
- forecast: estimated impressions at different bid levels (best-effort)
|
|
77
|
+
- creative_format_ids: required creative formats
|
|
78
|
+
- targeting: available audiences and contexts
|
|
79
|
+
|
|
80
|
+
sample_request:
|
|
81
|
+
buying_mode: "brief"
|
|
82
|
+
brief: "Display and video inventory across sports and outdoor lifestyle sites. Q2 flight, $25K budget. Adults 25-54, US. Auction-based, looking for competitive CPMs."
|
|
83
|
+
brand:
|
|
84
|
+
domain: "acmeoutdoor.com"
|
|
85
|
+
account:
|
|
86
|
+
brand:
|
|
87
|
+
domain: "acmeoutdoor.com"
|
|
88
|
+
operator: "pinnacle-agency.com"
|
|
89
|
+
|
|
90
|
+
validations:
|
|
91
|
+
- check: response_schema
|
|
92
|
+
description: "Response matches get-products-response.json schema"
|
|
93
|
+
- check: field_present
|
|
94
|
+
path: "products"
|
|
95
|
+
description: "Response contains a products array"
|
|
96
|
+
- check: field_present
|
|
97
|
+
path: "products[0].product_id"
|
|
98
|
+
description: "Each product has a product_id"
|
|
99
|
+
- check: field_present
|
|
100
|
+
path: "products[0].delivery_type"
|
|
101
|
+
description: "Each product declares delivery_type: non_guaranteed"
|
|
102
|
+
|
|
103
|
+
- id: create_buy
|
|
104
|
+
title: "Create non-guaranteed buy"
|
|
105
|
+
narrative: |
|
|
106
|
+
The buyer creates a media buy with bid prices per package. Since this is
|
|
107
|
+
non-guaranteed, no IO is required and no human approval is needed. The response
|
|
108
|
+
comes back as completed — the buy is immediately active and your platform starts
|
|
109
|
+
bidding in auctions on the buyer's behalf.
|
|
110
|
+
|
|
111
|
+
steps:
|
|
112
|
+
- id: create_media_buy
|
|
113
|
+
title: "Create a media buy with bid prices"
|
|
114
|
+
narrative: |
|
|
115
|
+
The buyer commits to non-guaranteed products with bid prices and budgets.
|
|
116
|
+
Your platform validates the bids against floor prices, confirms the buy
|
|
117
|
+
immediately (completed status), and begins auction participation.
|
|
118
|
+
|
|
119
|
+
Each package includes a bid_price that the buyer is willing to pay per unit
|
|
120
|
+
(CPM, CPC, etc.). The platform uses this to compete in auctions.
|
|
121
|
+
task: create_media_buy
|
|
122
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
123
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
124
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
125
|
+
stateful: true
|
|
126
|
+
expected: |
|
|
127
|
+
Return the media buy in completed status:
|
|
128
|
+
- media_buy_id: your platform's identifier
|
|
129
|
+
- status: confirmed or active (no async approval needed)
|
|
130
|
+
- confirmed_at: timestamp
|
|
131
|
+
- packages: confirmed line items with bid prices acknowledged
|
|
132
|
+
- valid_actions: pause, update_bid, get_delivery
|
|
133
|
+
|
|
134
|
+
Bids below floor_price should be rejected with a clear error.
|
|
135
|
+
|
|
136
|
+
sample_request:
|
|
137
|
+
account:
|
|
138
|
+
brand:
|
|
139
|
+
domain: "acmeoutdoor.com"
|
|
140
|
+
operator: "pinnacle-agency.com"
|
|
141
|
+
brand:
|
|
142
|
+
domain: "acmeoutdoor.com"
|
|
143
|
+
start_time: "2026-04-01T00:00:00Z"
|
|
144
|
+
end_time: "2026-06-30T23:59:59Z"
|
|
145
|
+
packages:
|
|
146
|
+
- product_id: "sports_display_auction"
|
|
147
|
+
budget: 10000
|
|
148
|
+
bid_price: 8.50
|
|
149
|
+
pricing_option_id: "cpm_auction"
|
|
150
|
+
creative_assignments:
|
|
151
|
+
- creative_id: "display_trail_pro_300x250"
|
|
152
|
+
- product_id: "outdoor_video_auction"
|
|
153
|
+
budget: 15000
|
|
154
|
+
bid_price: 22.00
|
|
155
|
+
pricing_option_id: "cpm_auction"
|
|
156
|
+
creative_assignments:
|
|
157
|
+
- creative_id: "video_30s_trail_pro"
|
|
158
|
+
|
|
159
|
+
validations:
|
|
160
|
+
- check: response_schema
|
|
161
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
162
|
+
|
|
163
|
+
- id: monitor_pacing
|
|
164
|
+
title: "Monitor win rates and pacing"
|
|
165
|
+
narrative: |
|
|
166
|
+
The non-guaranteed buy is live and bidding in auctions. The buyer checks
|
|
167
|
+
pacing to understand how competitive their bids are and whether the budget
|
|
168
|
+
is spending at the desired rate.
|
|
169
|
+
|
|
170
|
+
steps:
|
|
171
|
+
- id: get_media_buys_pacing
|
|
172
|
+
title: "Check buy status and pacing"
|
|
173
|
+
narrative: |
|
|
174
|
+
The buyer polls for the media buy status. Your platform returns the active
|
|
175
|
+
buy with pacing data — how much budget has been spent, win rates, and whether
|
|
176
|
+
the buy is on pace to exhaust the budget by the end of the flight.
|
|
177
|
+
task: get_media_buys
|
|
178
|
+
schema_ref: "media-buy/get-media-buys-request.json"
|
|
179
|
+
response_schema_ref: "media-buy/get-media-buys-response.json"
|
|
180
|
+
doc_ref: "/media-buy/task-reference/get_media_buys"
|
|
181
|
+
stateful: true
|
|
182
|
+
expected: |
|
|
183
|
+
Return the media buy with pacing data:
|
|
184
|
+
- media_buy_id: matches the buy created earlier
|
|
185
|
+
- status: active
|
|
186
|
+
- packages: line items with current spend, win rate, and pacing status
|
|
187
|
+
- valid_actions: update, pause, get_delivery
|
|
188
|
+
|
|
189
|
+
sample_request:
|
|
190
|
+
account:
|
|
191
|
+
brand:
|
|
192
|
+
domain: "acmeoutdoor.com"
|
|
193
|
+
operator: "pinnacle-agency.com"
|
|
194
|
+
media_buy_ids:
|
|
195
|
+
- "mb_acme_q2_2026_auction"
|
|
196
|
+
|
|
197
|
+
validations:
|
|
198
|
+
- check: response_schema
|
|
199
|
+
description: "Response matches get-media-buys-response.json schema"
|
|
200
|
+
- check: field_present
|
|
201
|
+
path: "media_buys[0].status"
|
|
202
|
+
description: "Media buy has a status"
|
|
203
|
+
|
|
204
|
+
- id: adjust_bids
|
|
205
|
+
title: "Adjust bids and budget"
|
|
206
|
+
narrative: |
|
|
207
|
+
Based on pacing data, the buyer adjusts bids or budgets in-flight. If a package
|
|
208
|
+
is underspending (low win rate), the buyer increases the bid. If a package is
|
|
209
|
+
overspending, the buyer decreases the bid or caps the daily budget.
|
|
210
|
+
|
|
211
|
+
steps:
|
|
212
|
+
- id: update_media_buy
|
|
213
|
+
title: "Update bid prices and budget"
|
|
214
|
+
narrative: |
|
|
215
|
+
The buyer modifies the active media buy — adjusting bid prices, reallocating
|
|
216
|
+
budget between packages, or changing daily spend caps. Your platform applies
|
|
217
|
+
the updates immediately to the live auction participation.
|
|
218
|
+
task: update_media_buy
|
|
219
|
+
schema_ref: "media-buy/update-media-buy-request.json"
|
|
220
|
+
response_schema_ref: "media-buy/update-media-buy-response.json"
|
|
221
|
+
doc_ref: "/media-buy/task-reference/update_media_buy"
|
|
222
|
+
stateful: true
|
|
223
|
+
expected: |
|
|
224
|
+
Apply the updates and return the modified media buy:
|
|
225
|
+
- media_buy_id: matches the existing buy
|
|
226
|
+
- status: active (still running)
|
|
227
|
+
- packages: updated line items reflecting new bids and budgets
|
|
228
|
+
- Changes take effect immediately for subsequent auctions
|
|
229
|
+
|
|
230
|
+
sample_request:
|
|
231
|
+
account:
|
|
232
|
+
brand:
|
|
233
|
+
domain: "acmeoutdoor.com"
|
|
234
|
+
operator: "pinnacle-agency.com"
|
|
235
|
+
media_buy_id: "mb_acme_q2_2026_auction"
|
|
236
|
+
packages:
|
|
237
|
+
- product_id: "sports_display_auction"
|
|
238
|
+
bid_price: 10.00
|
|
239
|
+
budget: 12000
|
|
240
|
+
- product_id: "outdoor_video_auction"
|
|
241
|
+
bid_price: 20.00
|
|
242
|
+
budget: 13000
|
|
243
|
+
|
|
244
|
+
validations:
|
|
245
|
+
- check: response_schema
|
|
246
|
+
description: "Response matches update-media-buy-response.json schema"
|
|
247
|
+
|
|
248
|
+
- id: delivery
|
|
249
|
+
title: "Delivery and auction metrics"
|
|
250
|
+
narrative: |
|
|
251
|
+
The buyer reviews delivery data including auction-specific metrics: win rates,
|
|
252
|
+
average clearing prices, and bid competitiveness across packages.
|
|
253
|
+
|
|
254
|
+
steps:
|
|
255
|
+
- id: get_delivery
|
|
256
|
+
title: "Check delivery with auction metrics"
|
|
257
|
+
narrative: |
|
|
258
|
+
The buyer requests delivery data for the active non-guaranteed media buy.
|
|
259
|
+
Your platform returns standard delivery metrics plus auction-specific data:
|
|
260
|
+
win rates, average clearing prices, bid-to-win ratios, and budget pacing.
|
|
261
|
+
task: get_media_buy_delivery
|
|
262
|
+
schema_ref: "media-buy/get-media-buy-delivery-request.json"
|
|
263
|
+
response_schema_ref: "media-buy/get-media-buy-delivery-response.json"
|
|
264
|
+
doc_ref: "/media-buy/task-reference/get_media_buy_delivery"
|
|
265
|
+
stateful: true
|
|
266
|
+
expected: |
|
|
267
|
+
Return delivery metrics for the non-guaranteed media buy:
|
|
268
|
+
- Per-package delivery: impressions, clicks, spend
|
|
269
|
+
- Win rate: percentage of auctions won per package
|
|
270
|
+
- Average clearing price: what the buyer actually paid vs. bid price
|
|
271
|
+
- Pacing: on track, ahead, behind relative to budget and flight dates
|
|
272
|
+
- Budget utilization: spent vs. committed
|
|
273
|
+
|
|
274
|
+
sample_request:
|
|
275
|
+
account:
|
|
276
|
+
brand:
|
|
277
|
+
domain: "acmeoutdoor.com"
|
|
278
|
+
operator: "pinnacle-agency.com"
|
|
279
|
+
media_buy_ids:
|
|
280
|
+
- "mb_acme_q2_2026_auction"
|
|
281
|
+
include_package_daily_breakdown: true
|
|
282
|
+
|
|
283
|
+
validations:
|
|
284
|
+
- check: response_schema
|
|
285
|
+
description: "Response matches get-media-buy-delivery-response.json schema"
|
|
286
|
+
- check: field_present
|
|
287
|
+
path: "media_buys"
|
|
288
|
+
description: "Response contains media buy delivery data"
|