-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathllms.txt
More file actions
1618 lines (1128 loc) · 169 KB
/
Copy pathllms.txt
File metadata and controls
1618 lines (1128 loc) · 169 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Ad Context Protocol (AdCP)
> Generated at: 2026-08-08
> Library: @adcp/sdk v13.0.0-rc.9
> AdCP major version: 3
> Canonical URL: https://adcontextprotocol.github.io/adcp-client/llms.txt
> Note: the `Library` stamp reflects the package.json version at doc-generation time. The narrative below describes the surface that lands on the next-published minor — including any 6.7 helpers documented here ahead of the release tag.
> Note: generated error-code prose may include explicit SDK compatibility overlays applied by `scripts/lib/error-code-prose-overlays.ts` when bundled beta manifest wording lags SDK behavior.
## What is AdCP
AdCP is an open protocol for AI agents to buy, manage, and optimize advertising programmatically. It defines MCP tools that agents call on publisher ad servers — discover inventory, create media buys, sync creatives, manage brand safety, and track delivery. Every tool follows request/response JSON schemas; the TypeScript client wraps them with async task handling, conversation context, and governance middleware.
## Are you building a client or a server?
- **Client** (calling existing agents): Continue reading — the Quick Start below is for you.
- **Server** (implementing an agent that others call): Read `docs/guides/BUILD-AN-AGENT.md` and `docs/migration-5.x-to-6.x.md`. v6 recommended path:
```typescript
import { serve } from '@adcp/sdk';
import {
createAdcpServerFromPlatform,
definePlatform,
defineSignalsPlatform,
} from '@adcp/sdk/server';
const platform = definePlatform({
capabilities: {
specialisms: ['signal-marketplace'] as const,
pricingModels: ['cpm'] as const,
},
accounts: {
resolve: async () => ({ id: 'acc_1', ctx_metadata: {} }),
},
signals: defineSignalsPlatform({
getSignals: async (req, ctx) => ({ signals: [/* ... */], sandbox: true }),
activateSignal: async (req, ctx) => ({ /* ... */ }),
}),
});
serve(() => createAdcpServerFromPlatform(platform, {
name: 'My Signals Agent',
version: '1.0.0',
})); // http://localhost:3001/mcp
```
Compile-time enforcement: `RequiredPlatformsFor<S>` catches missing specialism methods. Capability projection auto-derives `get_adcp_capabilities` blocks (`audience_targeting`, `conversion_tracking`, `compliance_testing.scenarios`, etc.). Idempotency, RFC 9421 signing, async tasks, and status normalization are framework-owned. Synchronous terminal responses do not emit completion webhooks by default; `autoEmitCompletionWebhooks: true` is available only as a non-conformant compatibility extension.
Lower-level option: `createAdcpServer({ signals: { getSignals: ... } })` from `@adcp/sdk/server/legacy/v5` — handler-bag API. Still fully supported, the substrate the platform path calls into. Use when you need fine control over individual handlers, mid-migration from a v5 codebase, or custom-shaped tools the platform interface doesn't yet model. `wrapEnvelope(inner, { replayed, context, operationId })` from `@adcp/sdk/server` attaches protocol envelope fields with the per-error-code allowlist (IDEMPOTENCY_CONFLICT drops `replayed`).
**Identity helpers (drop `req: unknown` casts on inline platforms).** `definePlatform` / `defineSalesCorePlatform` / `defineSalesIngestionPlatform` / `defineSignalsPlatform` / `defineCreativeBuilderPlatform` / `defineCreativeAdServerPlatform` / `defineCampaignGovernancePlatform` / `defineContentStandardsPlatform` / `definePropertyListsPlatform` / `defineCollectionListsPlatform` / `defineBrandRightsPlatform` / `definePlatformWithCompliance` are pure identity helpers from `@adcp/sdk/server`. They force a concrete platform interface as the parameter type so TypeScript flows `req` / `ctx` typing into nested handler bodies. Class-pattern adopters with explicit property annotations (`sales: SalesCorePlatform<Meta> & SalesIngestionPlatform<Meta> = { ... }`) don't need them.
**Typed errors instead of `new AdcpError(code, ...)`.** `AuthMissingError`, `AuthInvalidError`, `PermissionDeniedError(action)`, `RateLimitedError(retryAfterSeconds)`, `ServiceUnavailableError`, `UnsupportedFeatureError(feature)`, `GovernanceDeniedError`, `PolicyViolationError`, `IdempotencyConflictError`, `InvalidRequestError`, `InvalidStateError`, plus the not-found family (`AccountNotFoundError`, `MediaBuyNotFoundError`, `PackageNotFoundError`, `ProductNotFoundError`, `CreativeNotFoundError`) and the budget / state family. `AuthRequiredError` remains as a deprecated `AUTH_REQUIRED` compatibility wrapper for older sellers; new seller code should use the split auth classes. Each maps to its wire error code with `recovery` baked in. Throw from platform methods. In `accounts.resolve`, use auth errors only for inbound authentication failures; missing sync linkage or unknown account references should stay `ACCOUNT_NOT_FOUND` / `null`.
**`composeMethod` cookbook.** To layer `before`/`after` hooks on a single platform method — short-circuit for caching, enrichment under `ext.*`, typed-error guards — use `composeMethod(inner, { before?, after? })` from `@adcp/sdk/server`. Stacking multiple guards: nest `composeMethod` calls (outer `before` runs first). Test patterns (mocking inner, asserting short-circuit, chained hooks, typed-error propagation): see [`docs/recipes/composeMethod-testing.md`](./recipes/composeMethod-testing.md). Pre-built `accounts.resolve` guards from the same package: `requireAccountMatch(predicate, opts)`, `requireAdvertiserMatch(getRoster, opts)`, `requireOrgScope(getAccountOrg, getCtxOrg, opts)`. Default deny returns `null` (indistinguishable from "not found"; guards against principal enumeration); opt in to `onDeny: 'throw'` for typed `PermissionDeniedError`.
**Four reference `AccountStore` shapes.** Pick the one whose onboarding model matches yours. **Shape A — `InMemoryImplicitAccountStore`**: `resolution: 'implicit'`, buyer-driven `sync_accounts` populates the auth-principal → accounts map. **Shape B — `createOAuthPassthroughResolver`**: `resolution: 'explicit'`, returns just the `resolve` function for adapters fronting an upstream OAuth listing endpoint (Snap, Meta, TikTok, LinkedIn — `extract bearer → GET /me/adaccounts → match by id`). **Shape C — `createRosterAccountStore`**: `resolution: 'explicit'`, returns a complete `AccountStore` for adopters who own the roster (storefront table, admin-UI-managed JSON). Supports `resolveWithoutRef` for tools that send no `account` field on the wire (`list_creative_formats`, `preview_creative`, `provide_performance_feedback`) — set it to return a synthetic publisher-wide entry instead of `null`. **Shape D — `createDerivedAccountStore`**: `resolution: 'derived'`, single-tenant agents where there is no `account_id` on the wire and the auth principal alone identifies the tenant (audiostack, flashtalking, single-namespace retail-media). Provide `toAccount(ctx)`; the factory still emits legacy-compatible `AUTH_REQUIRED` on missing-credential calls and ignores buyer-supplied `account_id` (single-tenant by definition). Buyer code must continue to handle `AUTH_REQUIRED` alongside `AUTH_MISSING` / `AUTH_INVALID`. All four live at `@adcp/sdk/server`.
**Stateless BYOK provider auth.** For single-account API-key or bearer-token BYOK, the provider credential can be the AdCP request credential for that endpoint: `Authorization: Bearer <provider_api_key_or_access_token>`. This keeps the baseline seller-agent wrapper pattern single-plane: the seller agent authenticates the request with the caller-presented provider credential, derives the account from request auth, and uses the same request-local token for upstream provider calls. No SDK-managed OAuth flow, refresh-token store, provider-token store, or callback route is required when the caller owns the provider credential lifecycle. If the provider credential can see multiple upstream accounts, use an explicit account roster pattern such as `createOAuthPassthroughResolver` instead of `'derived'`. Handlers with a resolved account should read the active token from `ctx.account.authInfo?.token`; refresh hooks update `account.authInfo`. Handlers without a resolved account can read the request token from `ctx.authInfo.token`. Use a stable non-secret identity such as `ctx.authInfo.credential.key_id`, `ctx.authInfo.credential.client_id`, or an adopter-supplied `principal` string for cache/idempotency scoping. Treat both token paths as request-local: do not copy provider tokens into persisted Account rows, `ctx_metadata`, `ctx.authInfo.extra`, request `ext` / body fields, or log lines. Add a separate provider-auth channel only for dual-auth proxy deployments where one request carries both caller-to-agent auth and a distinct upstream-provider credential.
**Multi-tenant.** Two helpers, pick by deployment shape. **Host-routed**: `createTenantRegistry({...})` — one server per tenant, tenant-id keyed lookup with `registry.get(tenantId)`. **Account-routed**: `createTenantStore({...})` — one server, per-entry tenant-isolation gate built in (cross-tenant entries on `upsert` / `syncGovernance` rejected with `PERMISSION_DENIED` BEFORE adopter callbacks run; fail-closed when the auth principal can't be resolved). `createTenantStore` mitigates the canonical multi-tenant write-across-tenants bug class at the SDK layer rather than relying on adopter discipline.
**`BuyerAgentRegistry`** — durable buyer-agent identity surface. `BuyerAgentRegistry.signingOnly({ resolveByAgentUrl })` (production target — only `http_sig` credentials route through), `bearerOnly({ resolveByCredential })` (pre-trust beta — bearer/api-key/oauth all route), `mixed(...)` (transition posture). Wrap with `BuyerAgentRegistry.cached(inner, { ttlSeconds })` for TTL + LRU + concurrent-resolve coalescing. The resolved `BuyerAgent` flows through `ctx.agent` to every `AccountStore` method (`resolve` / `upsert` / `list` / `syncGovernance` / `reportUsage` / `getAccountFinancials`) and to `tasks_get` polling. `BuyerAgent.status === 'suspended' | 'blocked'` triggers framework-level `PERMISSION_DENIED`. `BuyerAgent.sandbox_only: true` rejects requests against non-sandbox accounts. See [`docs/migration-buyer-agent-registry.md`](./migration-buyer-agent-registry.md) for the full surface.
**Lifecycle helpers.** `MEDIA_BUY_TRANSITIONS` and `CREATIVE_ASSET_TRANSITIONS` (the canonical state-graph maps the storyboard runner uses), plus `isLegalMediaBuyTransition(from, to)` / `assertMediaBuyTransition(from, to)` and the creative pair. `assertMediaBuyTransition` throws `AdcpError` with the spec-correct code (`NOT_CANCELLABLE` for the cancel-idempotency path, `INVALID_STATE` everywhere else). Production sellers that enforce transitions with these helpers cannot drift from conformance enforcement. `createMediaBuyStore({ store })` opt-in framework wiring handles the `packages[].targeting_overlay` echo contract on `get_media_buys` (sellers claiming `property-lists` / `collection-lists` MUST echo the persisted list reference).
**Breaking in 6.7 — audit before bumping.** (1) `accounts.resolution: 'implicit'` now actually refuses inline `{account_id}` references with `INVALID_REQUEST` (pre-6.7 the docstring claimed this but nothing checked it). Adopters whose callers passed inline `account_id` against an `'implicit'` platform must drop to `'explicit'` or fix callers to use `sync_accounts` first. (2) `SalesPlatform` is now structurally `SalesCorePlatform & SalesIngestionPlatform` with all methods individually optional. Adopters with `: SalesPlatform<Meta>` field annotations claiming `sales-non-guaranteed` / `-guaranteed` / `-broadcast-tv` / `-catalog-driven` need to switch the annotation to `: SalesCorePlatform<Meta> & SalesIngestionPlatform<Meta>` (or use `defineSalesCorePlatform` + `defineSalesIngestionPlatform` spread). Self-announcing under `tsc --noEmit`. Walled-garden CAPI specialisms (`sales-social`) drop ~40 LOC of stub-throw boilerplate. Full migration recipe at [`docs/migration-6.6-to-6.7.md`](./migration-6.6-to-6.7.md).
**`Account<TCtxMeta>` v3 wire fields.** `Account` gained `billing_entity`, `rate_card`, `payment_terms`, `credit_limit`, `setup` (drives `pending_approval` → `active` lifecycle), `account_scope`, `governance_agents`, and `reporting_bucket` — all optional. `billing_entity.bank` and `governance_agents[i].authentication.credentials` are stripped on emit per spec; `Account.authInfo` is now optional. `AccountStore.upsert` / `list` / `syncGovernance` accept an optional `ResolveContext` second argument carrying `authInfo` / `toolName` / `agent` for principal-keyed gating.
**`refAccountId(ref)`** narrows `AccountReference` to its `account_id` arm without casting (returns `undefined` for missing refs, `{brand, operator}` arms, sandbox arms). `narrowAccountRef(ref)` returns the typed arm or `null` for full discriminated-union narrowing. **`NoAccountCtx<TCtxMeta>`** is the request-context type for tools whose wire request doesn't carry an `account` field (`previewCreative`, `listCreativeFormats`, `providePerformanceFeedback`); `ctx.account` is `Account<TCtxMeta> | undefined` and adopters either return a singleton from `accounts.resolve(undefined)` or guard with `if (ctx.account == null) ...`.
**Validation hints on every `VALIDATION_ERROR` envelope.** `ValidationIssue` carries `hint` (one-sentence curated recipe for known shape gotchas — `activation_key` discriminator nesting, `account` discriminator merging, `budget` shape, `format_id` object, VAST/DAAST `delivery_type`, missing `idempotency_key`, log_event/CAPI projection), `discriminator` (which `oneOf` branch the validator inferred), and `schemaId` (the `$id` of the rejecting schema). Buyer-side recovery order: `hint` first, then `discriminator`, then `variants`, then `pointer` + `keyword`. `oneOf` near-miss diagnostics now point at the Success-arm residuals when a Success-vs-Error envelope payload populates Success-only fields.
**Other adopter-facing surfaces.** `DecisioningPlatform.instructions` accepts a function form (`(ctx: SessionContext) => string | undefined`) for per-session prose under `serve({ reuseAgent: false })`. `listCreativeFormats?` is now typed on `CreativeBuilderPlatform` and `CreativeAdServerPlatform` (drops the v5 `opts.creative.listCreativeFormats` escape hatch). `update_rights` is a first-class brand-rights tool with `creative_approval` webhook builders. `@adcp/sdk/upstream-recorder` is a sandbox-only producer-side middleware for the `query_upstream_traffic` storyboard check; `@adcp/sdk/mock-server` is a public sub-export for in-process integration tests. `runStoryboard({ agents })` routes per-specialism storyboard steps to multiple agents (matching `/sales`, `/signals`, `/governance`, `/creative`, `/brand` topology). `media_buy_ids[]` fan-out on `getMediaBuyDelivery` / `getCreativeDelivery` is platform-side pass-through (framework hands the array as-is); a dev-mode warning fires when handlers return fewer rows than requested.
**Don't put credentials in `ctx_metadata`.** Wire-strip protects buyer responses but not server-side log lines, error envelopes, heap dumps, or adopter-generated strings. Re-derive bearers per request from `ctx.authInfo` + your token cache; embed only non-secret upstream IDs in `ctx_metadata`. See [`docs/guides/CTX-METADATA-SAFETY.md`](./guides/CTX-METADATA-SAFETY.md).
## Quick Start (Client)
```typescript
import { ADCPMultiAgentClient } from '@adcp/sdk';
const client = ADCPMultiAgentClient.simple('https://agent.example.com/mcp/', {
authToken: process.env.ADCP_TOKEN,
});
const agent = client.agent('default-agent');
// Discover products
const products = await agent.getProducts({ buying_mode: 'brief', brief: 'coffee brands' });
if (products.status === 'completed') console.log(products.data.products);
// Create a media buy
const buy = await agent.createMediaBuy({
account: { account_id: 'acct_1' },
brand: { domain: 'coffee.example.com' },
start_time: 'asap',
end_time: '2026-06-01T00:00:00Z',
packages: [{ buyer_ref: 'pkg-1', product_id: 'prod_1', pricing_option_id: 'cpm_1', budget: 5000 }],
});
```
## Canonical Reference Resolver
`format_schema` and `platform_extensions` references use immutable `{ uri, digest }` pointers. Use `createCanonicalReferenceResolver` from `@adcp/sdk/canonical-references` instead of raw fetches; it applies SSRF-safe DNS-pinned fetches, redirect blocking, timeout/body caps, SHA-256 verification, structured non-throwing statuses, and caller-owned policy-scoped caching.
```typescript
import { createCanonicalReferenceResolver } from '@adcp/sdk/canonical-references';
const resolver = createCanonicalReferenceResolver();
const formatSchemaRef = {
uri: 'https://publisher.example-ad.com/schemas/slot.json',
digest: 'sha256:<64 lowercase hex chars>',
};
const result = await resolver.resolveFormatSchema(formatSchemaRef, {
externalRefDigests: {
'https://publisher.example-ad.com/shared-slot.json': 'sha256:<64 lowercase hex chars>',
},
});
if (!result.ok) {
if (result.error.code === 'digest_mismatch') throw new Error('Reference substitution detected');
if (result.error.retryable) /* retry later */;
}
```
For `format_schema`, the resolver requires an explicit `$schema`, validates Draft-07 / Draft 2020-12 JSON Schema, inlines only pinned safe `$ref` targets, rejects known catastrophic regex patterns with `error.code: 'budget_exceeded'`, and returns `schemaMeta` on success. Failure statuses are coarse (`unresolvable`, `invalid_document`, `invalid_schema`, `digest_mismatch`, `blocked_unsafe_url`, `invalid_ref`); branch on `error.code` for precise handling. See `docs/guides/CANONICAL-REFERENCE-RESOLVER.md`.
## Transport auth
AdCP is auth-scheme-agnostic at the transport layer. The protocol carries JSON-RPC over HTTP; how the outer envelope is gated is an operator-private deployment choice — bearer tokens, OAuth, mTLS, AWS SigV4 at the edge, an IP allow-list, or RFC 7617 HTTP Basic when the agent sits behind an API gateway with a BasicAuthentication policy (Apigee, Kong, AWS API Gateway, nginx `auth_basic`) are all valid. `get_adcp_capabilities` does NOT advertise the accepted auth schemes; encoding every gateway permutation in the capability payload would couple the protocol to infrastructure choices that change between deployments.
Auth-scheme discovery, when needed, flows through `WWW-Authenticate` (RFC 9110 §11.6.1) and Protected Resource Metadata (RFC 9728) — both consumed by the SDK's auth-diagnostics path. Basic-fronted agents emit `WWW-Authenticate: Basic realm="…"` on a 401; consumers (SDK callers, the CLI's 401-bounce path, LLM agents) should branch on the challenge scheme rather than retrying Bearer indefinitely.
The TypeScript SDK speaks both schemes today. Programmatically: `createTestClient({ auth: { type: 'basic', username, password } })` (RFC 7617) and `createTestClient({ auth: { type: 'bearer', token } })`. From the CLI: `--auth-scheme basic` opts into Basic and `--auth <user:pass>` carries the credential; the default `bearer` remains unchanged.
## Error Handling
When `result.success` is `false`, use `result.adcpError` for programmatic handling:
- `result.error` — Human-readable string (e.g., `"RATE_LIMITED: Too many requests"`)
- `result.adcpError.code` — Error code (e.g., `RATE_LIMITED`, `INVALID_REQUEST`)
- `result.adcpError.recovery` — `'transient'` (retry), `'correctable'` (fix request), or `'terminal'` (give up)
- `result.adcpError.retryAfterMs` — Milliseconds to wait before retrying
- `result.adcpError.field` / `result.adcpError.suggestion` — Hints for correctable errors
- `result.adcpError.synthetic` — `true` when inferred from unstructured text
- `result.correlationId` — Correlation ID for tracing across agents
Use `isRetryable(result)` and `getRetryDelay(result)` for retry logic. `TaskResult` is a discriminated union — `if (result.success)` narrows `data` to `T`; `if (!result.success)` guarantees `error: string` and `status: 'failed'`.
```typescript
if (!result.success) {
if (isRetryable(result)) {
await sleep(getRetryDelay(result)); // ms, defaults to 5000
} else if (result.adcpError?.recovery === 'correctable') {
console.log('Fix:', result.adcpError.suggestion, 'Field:', result.adcpError.field);
} else {
console.error(result.error, 'Correlation:', result.correlationId);
}
}
```
For exhaustive handling across all seven statuses, prefer the `match()` dispatcher (fluent method on every result returned from the SDK, or free function import):
```typescript
const label = result.match!({
completed: r => `OK: ${JSON.stringify(r.data)}`,
failed: r => `Error: ${r.adcpError?.code ?? r.error}`,
submitted: r => `Pending: poll ${r.metadata.taskId}`,
'governance-denied': r => `Denied: ${r.adcpError?.code ?? r.error}`,
working: r => `Running: ${r.metadata.taskId}`,
'input-required': r => `Needs input: ${r.metadata.inputRequest?.question}`,
deferred: r => `Deferred: ${r.deferred?.token}`,
});
// Optional `_` catchall makes every arm optional:
// const label = result.match!({ completed: r => JSON.stringify(r.data), _: r => r.status });
```
TypeScript enforces exhaustiveness at compile time when the `_` catchall is omitted — missing an arm is a type error, not a runtime surprise. The `!` is because `TaskResultBase.match` is declared optional so hand-constructed result literals (tests, middleware) stay valid; every result returned from the SDK has `.match` attached. For hand-constructed literals, use the free function `match(result, handlers)` or call `attachMatch(result)` first.
## Idempotency (mutating requests)
AdCP v3 requires `idempotency_key` on every mutating request (`create_media_buy`, `update_media_buy`, `activate_signal`, all `sync_*`, `si_send_message`, etc.). The SDK auto-generates a UUID v4 when callers don't supply one, reuses it across internal retries, and surfaces it on the result:
```typescript
const result = await client.createMediaBuy({ account, brand, start_time, end_time, packages });
result.metadata.idempotency_key // key that was sent (auto-generated or caller-supplied)
result.metadata.replayed // true if this was a cached replay from a prior retry
```
**Two things agents with side effects MUST handle:**
1. **Side-effect suppression on `replayed: true`.** If your agent emits notifications, writes LLM memory, or fires downstream tool calls on the response, check `result.metadata.replayed` before acting. A cached replay means the side effects already fired on the original call.
```typescript
if (result.success && !result.metadata.replayed) {
await notify(`Campaign ${result.data.media_buy_id} created`);
await memory.write({ campaign_id: result.data.media_buy_id });
}
```
2. **Agent re-plan vs. network retry.** A network retry (same bytes, socket timeout) reuses the same key — the SDK handles this. An agent re-plan (LLM re-ran its planner and produced a different payload) means a NEW intent — mint a fresh key by calling the method again without passing one. Reusing the prior key with a different payload returns `IdempotencyConflictError`.
**Typed errors:** on failure, `result.errorInstance` carries a typed `ADCPError` subclass for codes with dedicated classes — currently `IdempotencyConflictError` and `IdempotencyExpiredError`. Prefer `instanceof` checks over switching on `adcpError.code` strings.
```typescript
import { IdempotencyConflictError, IdempotencyExpiredError } from '@adcp/sdk';
if (result.errorInstance instanceof IdempotencyConflictError) {
// Agent re-planned with different payload. Retry with a fresh key.
// result.errorInstance.idempotencyKey carries the key the server omitted.
}
if (result.errorInstance instanceof IdempotencyExpiredError) {
// Key past replay window. If you know the prior call succeeded, look up
// by natural key (e.g., get_media_buys by context.internal_campaign_id).
// Otherwise mint a fresh key.
}
```
**BYOK** (persist keys in your DB across process restarts): you own the replay-window boundary. Ask the client for the seller's declared TTL:
```typescript
const ttl = await client.getIdempotencyReplayTtlSeconds();
// Returns the declared number. Throws ConfigurationError if the seller is v3
// but omits adcp.idempotency.replay_ttl_seconds — the SDK does NOT default to
// 24h, because a silent default misleads retry-sensitive flows. Returns
// undefined on v2 sellers (pre-idempotency-envelope).
```
Pass your persisted key with `useIdempotencyKey(key)` — it validates against the spec pattern (`^[A-Za-z0-9_.:-]{16,255}$`) before the network round-trip:
```typescript
import { useIdempotencyKey } from '@adcp/sdk';
const key = await db.getOrCreateIdempotencyKey(campaign.id);
await client.createMediaBuy({ ...params, ...useIdempotencyKey(key) });
```
**Crash-recovery cookbook.** For an end-to-end recipe (natural-key lookup after restart, `IdempotencyConflictError` / `IdempotencyExpiredError` handling, `metadata.replayed` as side-effect gate, Postgres schema), see [`docs/guides/idempotency-crash-recovery.md`](./guides/idempotency-crash-recovery.md).
## ext.adcp Extension Namespace
**`ext.adcp.*` namespace.** The SDK reserves keys under `ext.adcp.*` for read-by-agent extensions that don't yet warrant their own AdCP spec field. Agents that recognize a key act on it; agents that don't recognize it ignore it silently (per AdCP `ext` semantics: accepted-without-error). The namespace is transport-neutral — it travels in the `ext` envelope field on both MCP and A2A transports. Keys in this namespace are hints **inbound to seller/responder agents** from the SDK or test tooling; **buyer agents building production flows MUST NOT emit `ext.adcp.*` keys**.
| Key | Stamped by | Purpose |
|-----|-----------|---------|
| `ext.adcp.disable_sandbox` | `adcp storyboard run --no-sandbox` | Hint (value: `true`) to bypass internal sandbox routing and exercise real adapter paths. Seller agents that honor this key serve production-shaped responses regardless of internal sandbox heuristics (env-var fallbacks, brand-domain detection, fixture substitutes). |
| `ext.adcp.creative_wire` | SDK storyboard/conformance tooling | Transitional 3.1 hint (value: `legacy` or `canonical`) for read requests whose creative dialect is otherwise structurally ambiguous. Application buyer agents do not emit this key; normal SDK methods negotiate from capabilities and payload shape. |
Third-party extensions MUST use a distinct namespace (e.g. `ext.com.example.*`) to avoid collisions with future `ext.adcp.*` keys.
## Tools
Every tool is an MCP tool called via `agent.<methodName>(params)`. Returns `TaskResult<T>` with `status`, `data`, `error`, `adcpError`, `correlationId`, `deferred`, or `submitted`.
### Protocol
#### `get_adcp_capabilities`
Request parameters for cross-protocol capability discovery.
**Request:**
- Optional: `protocols: string[]`, `context: Context`
**Response (success branch):**
- Required: `adcp: object`, `supported_protocols: string[]`
- Optional: `account: object`, `media_buy: object`, `signals: object`, `governance: object`, `sponsored_intelligence: object`, `brand: object`, `creative: object`, `request_signing: object`, +12 more
#### `get_task_status`
Request parameters for get_task_status, the 3.
**Request:**
- Required: `task_id: string`
- Optional: `account: Account Ref`, `include_history: boolean`, `include_result: boolean`, `context: Context`
**Response (success branch):**
- Required: `task_id: string`, `task_type: Task Type`, `protocol: Adcp Protocol`, `status: Task Status`, `created_at: string`, `updated_at: string`
- Optional: `completed_at: string`, `has_webhook: boolean`, `progress: object`, `error: object`, `history: object[]`, `result: Async Response Data`, `context: Context`
#### `list_tasks`
Request parameters for list_tasks, the 3.
**Request:**
- Optional: `account: Account Ref`, `filters: object`, `sort: object`, `pagination: Pagination Request`, `include_history: boolean`, `context: Context`
**Response (success branch):**
- Required: `query_summary: object`, `tasks: object[]`, `pagination: Pagination Response`
- Optional: `context: Context`
### Account Management
#### `list_accounts`
Request parameters for listing accounts accessible to the authenticated agent.
**Request:**
- Optional: `account: Account Ref`, `status: 'active' | 'pending_approval' | 'rejected' | 'payment_required' | 'suspended' | 'closed'`, `pagination: Pagination Request`, `sandbox: boolean`, `context: Context`
**Response (success branch):**
- Required: `accounts: object[]`
- Optional: `errors: object[]`, `pagination: Pagination Response`, `context: Context`
#### `sync_accounts`
Request parameters for syncing advertiser accounts with a seller.
**Request:**
- Required: `idempotency_key: string`, `accounts: object[]`
- Optional: `delete_missing: boolean`, `dry_run: boolean`, `push_notification_config: Push Notification Config`, `context: Context`
**Response (success branch):**
- Required: `accounts: object[]`
- Optional: `dry_run: boolean`, `context: Context`
#### `sync_governance`
Request parameters for registering governance agent endpoints on accounts.
**Request:**
- Required: `idempotency_key: string`, `accounts: object[]`
- Optional: `context: Context`
**Response (success branch):**
- Required: `accounts: object[]`
- Optional: `context: Context`
#### `report_usage`
Request parameters for reporting vendor service consumption after delivery.
**Request:**
- Required: `idempotency_key: string`, `reporting_period: Datetime Range`, `usage: object[]`
- Optional: `context: Context`
**Response (success branch):**
- Required: `accepted: integer`
- Optional: `errors: object[]`, `sandbox: boolean`, `context: Context`
#### `get_account_financials`
Request parameters for querying financial status of an operator-billed account.
**Request:**
- Required: `account: Account Ref`
- Optional: `period: Date Range`, `context: Context`
**Response (success branch):**
- Required: `account: Account Ref`, `currency: string`, `period: Date Range`, `timezone: string`
- Optional: `spend: object`, `credit: object`, `balance: object`, `payment_status: 'current' | 'past_due' | 'suspended'`, `payment_terms: Payment Terms`, `invoices: object[]`, `context: Context`
**Deep dive:**
- docs/getting-started.md — authentication and account setup
### Media Buying
#### `get_products`
Request parameters for discovering available advertising products.
**Request:**
- Required: `buying_mode: 'brief' | 'wholesale' | 'refine'`
- Optional: `brief: string`, `refine: object[]`, `brand: Brand Ref`, `catalog: Catalog`, `account: Account Ref`, `preferred_delivery_types: object[]`, `filters: Product Filters`, `property_list: Property List Ref`, +8 more
**Response (success branch):**
- Optional: `products: object[]`, `extensions: object`, `proposals: object[]`, `errors: object[]`, `property_list_applied: boolean`, `catalog_applied: boolean`, `refinement_applied: object[]`, `incomplete: object[]`, +8 more
**Watch out:**
- `cache_scope` is required whenever the response includes `products` or `unchanged: true`. Use `public` for the universal rate card and `account` for account-specific rate cards or pricing overlays.
- SDK server handlers may omit `cache_scope` only for no-account product feeds; the framework can safely infer `public` only when there is no inline account and no auth-derived/resolved account.
#### `list_creative_formats`
Request parameters for discovering format IDs and creative agents supported by this sales agent.
**Request:**
- Optional: `format_ids: object[]`, `asset_types: object[]`, `max_width: integer`, `max_height: integer`, `min_width: integer`, `min_height: integer`, `is_responsive: boolean`, `name_search: string`, +9 more
**Response (success branch):**
- Required: `formats: object[]`
- Optional: `source: 'publisher' | 'aao_mirror' | 'agent_derived'`, `creative_agents: object[]`, `errors: object[]`, `pagination: Pagination Response`, `sandbox: boolean`, `context: Context`
**Watch out:**
- Each `renders[]` entry satisfies a `oneOf` — exactly one of `dimensions` (object) OR `parameters_from_format_id: true`. A render with only `{ role }` (or `{ role, duration_seconds }`) fails validation.
- Use the typed factories from `@adcp/sdk`: `displayRender({ role, dimensions })` for display/video; `parameterizedRender({ role })` for audio and template formats (auto-injects `parameters_from_format_id: true`).
- Audio formats (`type: "audio"`) have no width/height — declare `renders: [parameterizedRender({ role: "primary" })]` and encode duration/codec in `format_id.parameters` (declared via `accepts_parameters`).
#### `create_media_buy`
Request parameters for creating a media buy.
**Request:**
- Required: `idempotency_key: string`, `account: Account Ref`, `brand: Brand Ref`, `start_time: Start Timing`, `end_time: string`
- Optional: `plan_id: string`, `proposal_id: string`, `total_budget: object`, `packages: object[]`, `advertiser_industry: Advertiser Industry`, `invoice_recipient: Business Entity`, `io_acceptance: object`, `po_number: string`, +6 more
**Response (success branch):**
- Required: `media_buy_id: string`, `confirmed_at: string,null`, `revision: integer`, `packages: object[]`
- Optional: `account: Account`, `invoice_recipient: Business Entity`, `media_buy_status: Media Buy Status`, `status: Media Buy Status`, `creative_deadline: string`, `currency: string`, `total_budget: number`, `valid_actions: object[]`, +4 more
**Watch out:**
- Server handlers should return business lifecycle state as `media_buy_status`. The framework owns the task envelope `status`; do not return top-level `status` as the media-buy state.
#### `update_media_buy`
Request parameters for updating campaign and package settings.
**Request:**
- Required: `account: Account Ref`, `media_buy_id: string`, `idempotency_key: string`
- Optional: `revision: integer`, `paused: boolean`, `canceled: 'true'`, `cancellation_reason: string`, `start_time: Start Timing`, `end_time: string`, `packages: object[]`, `invoice_recipient: Business Entity`, +4 more
**Response (success branch):**
- Required: `media_buy_id: string`, `revision: integer`
- Optional: `media_buy_status: Media Buy Status`, `status: Media Buy Status`, `currency: string`, `total_budget: number`, `implementation_date: string,null`, `invoice_recipient: Business Entity`, `affected_packages: object[]`, `valid_actions: object[]`, +3 more
**Watch out:**
- Server handlers should return business lifecycle state as `media_buy_status`. The framework owns the task envelope `status`; do not return top-level `status` as the media-buy state.
#### `get_media_buys`
Request parameters for retrieving media buy status, creative approvals, and delivery snapshots.
**Request:**
- Optional: `account: Account Ref`, `media_buy_ids: string[]`, `status_filter: Media Buy Status | object[]`, `include_snapshot: boolean`, `include_history: integer`, `include_webhook_activity: boolean`, `webhook_activity_limit: integer`, `pagination: Pagination Request`, +1 more
**Response (success branch):**
- Required: `media_buys: object[]`
- Optional: `errors: object[]`, `pagination: Pagination Response`, `sandbox: boolean`, `context: Context`
#### `get_media_buy_delivery`
Request parameters for retrieving comprehensive delivery metrics.
**Request:**
- Optional: `account: Account Ref`, `media_buy_ids: string[]`, `status_filter: Media Buy Status | object[]`, `start_date: string`, `end_date: string`, `include_package_daily_breakdown: boolean`, `time_granularity: Reporting Frequency`, `include_window_breakdown: boolean`, +3 more
**Response (success branch):**
- Required: `reporting_period: object`, `currency: string`, `media_buy_deliveries: object[]`
- Optional: `notification_type: 'scheduled' | 'final' | 'delayed' | 'adjusted' | 'window_update'`, `partial_data: boolean`, `unavailable_count: integer`, `sequence_number: integer`, `next_expected_at: string`, `attribution_window: Attribution Window`, `aggregated_totals: object`, `errors: object[]`, +2 more
#### `provide_performance_feedback`
Request parameters for sharing performance outcomes with publishers.
**Request:**
- Required: `media_buy_id: string`, `idempotency_key: string`, `measurement_period: Datetime Range`, `performance_index: number`
- Optional: `package_id: string`, `creative_id: string`, `metric_type: Metric Type`, `feedback_source: Feedback Source`, `context: Context`
**Response (success branch):**
- Required: `success: 'true'`
- Optional: `sandbox: boolean`, `context: Context`
#### `sync_event_sources`
Request parameters for configuring event sources on an account.
**Request:**
- Required: `idempotency_key: string`, `account: Account Ref`
- Optional: `event_sources: object[]`, `delete_missing: boolean`, `context: Context`
**Response (success branch):**
- Required: `event_sources: object[]`
- Optional: `sandbox: boolean`, `context: Context`
#### `log_event`
Request parameters for logging conversion or marketing events.
**Request:**
- Required: `event_source_id: string`, `events: object[]`, `idempotency_key: string`
- Optional: `test_event_code: string`, `context: Context`
**Response (success branch):**
- Required: `events_received: integer`, `events_processed: integer`
- Optional: `partial_failures: object[]`, `warnings: string[]`, `match_quality: number`, `sandbox: boolean`, `context: Context`
#### `sync_audiences`
Request parameters for managing CRM-based audiences on an account.
**Request:**
- Required: `idempotency_key: string`, `account: Account Ref`
- Optional: `audiences: object[]`, `delete_missing: boolean`, `context: Context`
**Response (success branch):**
- Required: `audiences: object[]`
- Optional: `sandbox: boolean`, `context: Context`
#### `sync_catalogs`
Request parameters for syncing catalog feeds (products, inventory, stores, promotions, offerings) with approval workflow.
**Request:**
- Required: `idempotency_key: string`, `account: Account Ref`
- Optional: `catalogs: object[]`, `catalog_ids: string[]`, `delete_missing: boolean`, `dry_run: boolean`, `validation_mode: Validation Mode`, `push_notification_config: Push Notification Config`, `context: Context`
**Response (success branch):**
- Required: `catalogs: object[]`
- Optional: `dry_run: boolean`, `sandbox: boolean`, `context: Context`
**Deep dive:**
- docs/getting-started.md — installation, auth, basic usage
- docs/guides/ASYNC-DEVELOPER-GUIDE.md — async task patterns (submitted, deferred, input-required)
- docs/guides/PUSH-NOTIFICATION-CONFIG.md — webhook setup for delivery reports
- docs/guides/REAL-WORLD-EXAMPLES.md — end-to-end buying flows
### Creative
#### `build_creative`
Request parameters for AI-powered creative generation.
**Request:**
- Required: `idempotency_key: string`
- Optional: `message: string`, `creative_manifest: Creative Manifest`, `creative_id: string`, `concept_id: string`, `media_buy_id: string`, `package_id: string`, `target_format_id: Format Id`, `target_format_ids: object[]`, +23 more
**Response (success branch):**
- Required: `creative_manifest: Creative Manifest`
- Optional: `build_variant_id: string`, `recipe_hash: string`, `sandbox: boolean`, `expires_at: string`, `preview: object`, `preview_error: Error`, `pricing_option_id: string`, `vendor_cost: number`, +3 more
**Watch out:**
- Response is ALWAYS `{ creative_manifest }` (single) or `{ creative_manifests }` (multi). Platform-native fields at the top level (`tag_url`, `creative_id`, `media_type`) are invalid.
- Use `buildCreativeResponse({ creative_manifest })` / `buildCreativeMultiResponse({ creative_manifests })` from `@adcp/sdk/server` to enforce the shape at compile time.
- Each asset under `creative_manifest.assets` needs an `asset_type` discriminator — use the factories: `imageAsset`, `videoAsset`, `audioAsset`, `htmlAsset`, `urlAsset`, `textAsset` (or `Asset.image(...)`).
#### `preview_creative`
Request parameters for generating creative previews.
**Request:**
- Required: `request_type: 'single' | 'batch' | 'variant'`
- Optional: `creative_manifest: Creative Manifest`, `format_id: Format Id`, `inputs: object[]`, `template_id: string`, `quality: Creative Quality`, `output_format: Preview Output Format`, `item_limit: integer`, `requests: object[]`, +3 more
**Response (success branch):**
- Required: `response_type: 'single'`, `previews: object[]`
- Optional: `interactive_url: string`, `expires_at: string`, `context: Context`
**Watch out:**
- Each `renders[]` entry is a oneOf on `output_format` — use `urlRender({...})`, `htmlRender({...})`, or `bothRender({...})` to inject the discriminator and require the matching `preview_url`/`preview_html` field.
#### `list_creative_formats`
Request parameters for discovering creative formats from this creative agent.
**Request:**
- Optional: `format_ids: object[]`, `type: 'audio' | 'video' | 'display' | 'dooh'`, `asset_types: object[]`, `max_width: integer`, `max_height: integer`, `min_width: integer`, `min_height: integer`, `is_responsive: boolean`, +10 more
**Response (success branch):**
- Required: `formats: object[]`
- Optional: `creative_agents: object[]`, `errors: object[]`, `pagination: Pagination Response`, `context: Context`
**Watch out:**
- Each `renders[]` entry satisfies a `oneOf` — exactly one of `dimensions` (object) OR `parameters_from_format_id: true`. A render with only `{ role }` (or `{ role, duration_seconds }`) fails validation.
- Use the typed factories from `@adcp/sdk`: `displayRender({ role, dimensions })` for display/video; `parameterizedRender({ role })` for audio and template formats (auto-injects `parameters_from_format_id: true`).
- Audio formats (`type: "audio"`) have no width/height — declare `renders: [parameterizedRender({ role: "primary" })]` and encode duration/codec in `format_id.parameters` (declared via `accepts_parameters`).
#### `list_transformers`
Request parameters for discovering account-scoped creative transformers (the creative analog of products), with optional brief filtering, per-param option expansion, and pricing.
**Request:**
- Optional: `transformer_ids: string[]`, `input_format_ids: object[]`, `output_format_ids: object[]`, `name_search: string`, `brief: string`, `expand_params: string[]`, `expand_pagination: object[]`, `include_pricing: boolean`, +3 more
**Response (success branch):**
- Required: `transformers: object[]`
- Optional: `errors: object[]`, `pagination: Pagination Response`, `context: Context`
#### `get_creative_delivery`
Request parameters for retrieving creative delivery data with variant-level breakdowns.
**Request:**
- Optional: `account: Account Ref`, `media_buy_ids: string[]`, `creative_ids: string[]`, `start_date: string`, `end_date: string`, `max_variants: integer`, `pagination: Pagination Request`, `context: Context`
**Response (success branch):**
- Required: `currency: string`, `reporting_period: object`, `creatives: object[]`
- Optional: `account_id: string`, `media_buy_id: string`, `pagination: object`, `errors: object[]`, `context: Context`
#### `list_creatives`
Request parameters for querying creative library with filtering and pagination.
**Request:**
- Optional: `filters: Creative Filters`, `sort: object`, `pagination: Pagination Request`, `include_assignments: boolean`, `include_snapshot: boolean`, `include_items: boolean`, `include_variables: boolean`, `include_pricing: boolean`, +6 more
**Response (success branch):**
- Required: `query_summary: object`, `pagination: Pagination Response`, `creatives: object[]`
- Optional: `format_summary: object`, `status_summary: object`, `errors: object[]`, `sandbox: boolean`, `context: Context`
#### `sync_creatives`
Request parameters for syncing creative assets with upsert semantics.
**Request:**
- Required: `account: Account Ref`, `creatives: object[]`, `idempotency_key: string`
- Optional: `creative_ids: string[]`, `assignments: object[]`, `delete_missing: boolean`, `dry_run: boolean`, `validation_mode: Validation Mode`, `push_notification_config: Push Notification Config`, `context: Context`
**Response (success branch):**
- Required: `creatives: object[]`
- Optional: `dry_run: boolean`, `sandbox: boolean`, `context: Context`
#### `validate_input`
Request parameters for validating a creative manifest against canonical formats and/or specific products without committing to a render.
**Request:**
- Required: `manifest: Creative Manifest`
- Optional: `account: Account Ref`, `brand: Brand Ref`, `targets: object[]`
**Response (success branch):**
- Required: `results: object[]`
**Deep dive:**
- docs/guides/BUILD-AN-AGENT.md — building a creative agent (server-side)
- schemas/cache/latest/creative/asset-types/index.json — asset type definitions
### Signals
#### `get_signals`
Request parameters for discovering signals based on description.
**Request:**
- Optional: `discovery_mode: 'brief' | 'wholesale'`, `account: Account Ref`, `signal_spec: string`, `signal_refs: object[]`, `signal_ids: object[]`, `destinations: object[]`, `countries: string[]`, `filters: Signal Filters`, +7 more
**Response (success branch):**
- Optional: `signals: object[]`, `errors: object[]`, `incomplete: object[]`, `wholesale_feed_version: string`, `pricing_version: string`, `cache_scope: 'public' | 'account'`, `unchanged: 'true'`, `pagination: Pagination Response`, +2 more
#### `activate_signal`
Request parameters for activating a signal on a specific platform/account.
**Request:**
- Required: `signal_agent_segment_id: string`, `destinations: object[]`, `idempotency_key: string`
- Optional: `action: 'activate' | 'deactivate'`, `pricing_option_id: string`, `governance_context: string`, `account: Account Ref`, `context: Context`
**Response (success branch):**
- Required: `deployments: object[]`
- Optional: `sandbox: boolean`, `context: Context`
**Deep dive:**
- docs/guides/BUILD-AN-AGENT.md — signals agent example
### Governance
#### `create_property_list`
Request parameters for creating a new property list.
**Request:**
- Required: `name: string`, `idempotency_key: string`
- Optional: `account: Account Ref`, `description: string`, `base_properties: object[]`, `filters: Property List Filters`, `brand: Brand Ref`, `context: Context`
**Response (success branch):**
- Required: `list: Property List`, `auth_token: string`
- Optional: `replayed: boolean`, `context: Context`
#### `update_property_list`
Request parameters for updating an existing property list.
**Request:**
- Required: `list_id: string`, `idempotency_key: string`
- Optional: `account: Account Ref`, `name: string`, `description: string`, `base_properties: object[]`, `filters: Property List Filters`, `brand: Brand Ref`, `webhook_url: string`, `context: Context`
**Response (success branch):**
- Required: `list: Property List`
- Optional: `replayed: boolean`, `context: Context`
#### `get_property_list`
Request parameters for retrieving a property list with resolved properties.
**Request:**
- Required: `list_id: string`
- Optional: `account: Account Ref`, `resolve: boolean`, `pagination: object`, `context: Context`
**Response (success branch):**
- Required: `list: Property List`
- Optional: `identifiers: object[]`, `pagination: Pagination Response`, `resolved_at: string`, `cache_valid_until: string`, `coverage_gaps: object`, `context: Context`
#### `list_property_lists`
Request parameters for listing property lists.
**Request:**
- Optional: `account: Account Ref`, `name_contains: string`, `pagination: Pagination Request`, `context: Context`
**Response (success branch):**
- Required: `lists: object[]`
- Optional: `pagination: Pagination Response`, `context: Context`
#### `delete_property_list`
Request parameters for deleting a property list.
**Request:**
- Required: `list_id: string`, `idempotency_key: string`
- Optional: `account: Account Ref`, `context: Context`
**Response (success branch):**
- Required: `deleted: boolean`, `list_id: string`
- Optional: `replayed: boolean`, `context: Context`
#### `create_collection_list`
Request parameters for creating a new collection list.
**Request:**
- Required: `name: string`, `idempotency_key: string`
- Optional: `account: Account Ref`, `description: string`, `base_collections: object[]`, `filters: Collection List Filters`, `brand: Brand Ref`, `context: Context`
**Response (success branch):**
- Required: `list: Collection List`, `auth_token: string`
- Optional: `replayed: boolean`, `context: Context`
#### `update_collection_list`
Request parameters for updating an existing collection list.
**Request:**
- Required: `list_id: string`, `idempotency_key: string`
- Optional: `account: Account Ref`, `name: string`, `description: string`, `base_collections: object[]`, `filters: Collection List Filters`, `brand: Brand Ref`, `webhook_url: string`, `context: Context`
**Response (success branch):**
- Required: `list: Collection List`
- Optional: `replayed: boolean`, `context: Context`
#### `get_collection_list`
Request parameters for retrieving a collection list with resolved collections.
**Request:**
- Required: `list_id: string`
- Optional: `account: Account Ref`, `resolve: boolean`, `pagination: object`, `context: Context`
**Response (success branch):**
- Required: `list: Collection List`
- Optional: `collections: object[]`, `pagination: Pagination Response`, `resolved_at: string`, `cache_valid_until: string`, `coverage_gaps: object`, `context: Context`
#### `list_collection_lists`
Request parameters for listing collection lists.
**Request:**
- Optional: `account: Account Ref`, `name_contains: string`, `pagination: Pagination Request`, `context: Context`
**Response (success branch):**
- Required: `lists: object[]`
- Optional: `pagination: Pagination Response`, `context: Context`
#### `delete_collection_list`
Request parameters for deleting a collection list.
**Request:**
- Required: `list_id: string`, `idempotency_key: string`
- Optional: `account: Account Ref`, `context: Context`
**Response (success branch):**
- Required: `deleted: boolean`, `list_id: string`
- Optional: `replayed: boolean`, `context: Context`
#### `list_content_standards`
Request parameters for listing content standards configurations.
**Request:**
- Optional: `channels: object[]`, `languages: string[]`, `countries: string[]`, `pagination: Pagination Request`, `context: Context`
**Response (success branch):**
- Required: `standards: object[]`
- Optional: `pagination: Pagination Response`, `context: Context`
#### `get_content_standards`
Request parameters for retrieving a specific standards configuration.
**Request:**
- Required: `standards_id: string`
- Optional: `context: Context`
**Response (success branch):**
- Optional: `context: Context`
#### `create_content_standards`
Request parameters for creating a new content standards configuration.
**Request:**
- Required: `scope: object`, `idempotency_key: string`
- Optional: `registry_policy_ids: string[]`, `policies: object[]`, `calibration_exemplars: object`, `context: Context`
**Response (success branch):**
- Required: `standards_id: string`
- Optional: `context: Context`
#### `update_content_standards`
Request parameters for updating an existing content standards configuration.
**Request:**
- Required: `standards_id: string`, `idempotency_key: string`
- Optional: `scope: object`, `registry_policy_ids: string[]`, `policies: object[]`, `calibration_exemplars: object`, `context: Context`
**Response (success branch):**
- Required: `success: 'true'`, `standards_id: string`
- Optional: `context: Context`
#### `calibrate_content`
Request parameters for collaborative calibration dialogue.
**Request:**
- Required: `standards_id: string`, `artifact: Artifact`, `idempotency_key: string`
- Optional: `context: Context`
**Response (success branch):**
- Required: `verdict: Binary Verdict`
- Optional: `confidence: number`, `explanation: string`, `features: object[]`, `context: Context`
#### `validate_content_delivery`
Request parameters for batch validating delivery records.
**Request:**
- Required: `standards_id: string`, `records: object[]`
- Optional: `feature_ids: string[]`, `include_passed: boolean`, `context: Context`
**Response (success branch):**
- Required: `summary: object`, `results: object[]`
- Optional: `context: Context`
#### `get_media_buy_artifacts`
Request parameters for retrieving content artifacts from a media buy.
**Request:**
- Required: `media_buy_id: string`
- Optional: `account: Account Ref`, `package_ids: string[]`, `failures_only: boolean`, `time_range: object`, `pagination: object`, `context: Context`
**Response (success branch):**
- Required: `media_buy_id: string`, `artifacts: object[]`
- Optional: `collection_info: object`, `pagination: Pagination Response`, `context: Context`
#### `get_creative_features`
Request parameters for evaluating creative features from a governance agent.
**Request:**
- Required: `creative_manifest: Creative Manifest`
- Optional: `feature_ids: string[]`, `account: Account Ref`, `context: Context`
**Response (success branch):**
- Required: `results: object[]`
- Optional: `detail_url: string`, `audit_observations: object[]`, `pricing_option_id: string`, `vendor_cost: number`, `currency: string`, `consumption: Creative Consumption`, `context: Context`
#### `sync_plans`
Push campaign plans to the governance agent.
**Request:**
- Required: `idempotency_key: string`, `plans: object[]`
- Optional: `context: Context`
**Response (success branch):**
- Required: `plans: object[]`
- Optional: `replayed: boolean`, `context: Context`
#### `report_plan_outcome`
Report the outcome of an action to the governance agent.
**Request:**
- Required: `plan_id: string`, `idempotency_key: string`, `outcome: Outcome Type`, `governance_context: string`
- Optional: `check_id: string`, `purchase_type: Purchase Type`, `seller_response: object`, `delivery: object`, `error: object`, `context: Context`
**Response (success branch):**
- Required: `outcome_id: string`, `outcome_state: 'accepted' | 'findings'`
- Optional: `committed_budget: number`, `findings: object[]`, `plan_summary: object`, `replayed: boolean`, `context: Context`
#### `get_plan_audit_logs`
Retrieve governance state and audit trail for a plan.
**Request:**
- Optional: `plan_ids: string[]`, `portfolio_plan_ids: string[]`, `governance_contexts: string[]`, `purchase_types: object[]`, `include_entries: boolean`, `context: Context`
**Response (success branch):**
- Required: `plans: object[]`
- Optional: `context: Context`
#### `check_governance`
Orchestrator or seller calls the governance agent to validate an action against the campaign plan.
**Request:**
- Required: `plan_id: string`, `caller: string`
- Optional: `purchase_type: Purchase Type`, `tool: string`, `payload: object`, `governance_context: string`, `phase: Governance Phase`, `planned_delivery: Planned Delivery`, `delivery_metrics: object`, `modification_summary: string`, +2 more
**Response (success branch):**
- Required: `check_id: string`, `verdict: Governance Decision`, `plan_id: string`, `explanation: string`
- Optional: `findings: object[]`, `conditions: object[]`, `expires_at: string`, `next_check: string`, `categories_evaluated: string[]`, `policies_evaluated: string[]`, `mode: Governance Mode`, `governance_context: string`, +1 more
**Deep dive:**
- docs/guides/HANDLER-PATTERNS-GUIDE.md — input handler patterns for governance flows
### Sponsored Intelligence
#### `si_get_offering`
Get offering details, availability, and optionally matching products before session handoff.
**Request:**
- Required: `offering_id: string`
- Optional: `intent: string`, `context: Context`, `include_products: boolean`, `product_limit: integer`
**Response (success branch):**
- Required: `available: boolean`
- Optional: `offering_token: string`, `ttl_seconds: integer`, `checked_at: string`, `offering: object`, `matching_products: object[]`, `sponsored_context: Si Sponsored Context`, `total_matching: integer`, `unavailable_reason: string`, +3 more
#### `si_initiate_session`
Host initiates SI session with brand agent - includes context, identity, and capability negotiation.
**Request:**
- Required: `intent: string`, `identity: Si Identity`, `idempotency_key: string`
- Optional: `context: Context`, `media_buy_id: string`, `placement: string`, `offering_id: string`, `supported_capabilities: Si Capabilities`, `offering_token: string`, `sponsored_context_receipt: Si Sponsored Context Receipt`
**Response (success branch):**
- Required: `session_id: string`, `session_status: Si Session Status`
- Optional: `response: object`, `negotiated_capabilities: Si Capabilities`, `sponsored_context: Si Sponsored Context`, `session_ttl_seconds: integer`, `errors: object[]`, `context: Context`
#### `si_send_message`
Send a message within an active SI session.
**Request:**
- Required: `idempotency_key: string`, `session_id: string`
- Optional: `message: string`, `action_response: object`, `sponsored_context_receipt: Si Sponsored Context Receipt`, `context: Context`
**Response (success branch):**
- Required: `session_id: string`, `session_status: Si Session Status`
- Optional: `response: object`, `mcp_resource_uri: string`, `sponsored_context: Si Sponsored Context`, `handoff: object`, `errors: object[]`, `context: Context`
#### `si_terminate_session`
Terminate an SI session with reason (handoff_transaction, handoff_complete, user_exit, session_timeout, host_terminated).
**Request:**
- Required: `session_id: string`, `reason: 'handoff_transaction' | 'handoff_complete' | 'user_exit' | 'session_timeout' | 'host_terminated'`
- Optional: `termination_context: object`, `context: Context`
**Response (success branch):**
- Required: `session_id: string`, `terminated: boolean`
- Optional: `session_status: Si Session Status`, `acp_handoff: object`, `follow_up: object`, `errors: object[]`, `context: Context`
**Deep dive:**
- docs/guides/ASYNC-DEVELOPER-GUIDE.md — session lifecycle patterns
### Trusted Match (TMP)
Real-time execution layer. These are HTTP operations, not MCP tools.
#### `context_match`
Evaluate available packages against content context.
#### `identity_match`
Evaluate user eligibility for packages using an opaque identity token.
**AdCP 3.1.10 TMPX boundary:**
- Public `identity_match` calls return `IdentityMatchResponseRouterPublisher`: provider chunks are attributed under `tmpx_providers[provider_id].chunks`.
- Router implementations validate upstream identity providers with `IdentityMatchResponseProviderRouter`, whose root field is `tmpx_chunks`.
- Providers register local `tmpx_slots`; publisher-owned `PublisherTMPXMacroMapping` resolves each `(provider_id, slot_id)` to a local destination. Provider responses never carry publisher macro names.
- Both response hops forbid `context`/`ext` and opposite-hop TMPX fields. Chunk arrays contain one or two strict `{ slot_id, value }` entries.
## Common Flows
These are the standard tool call sequences from the AdCP storyboards. Each flow shows the tools called in order.
### Brand
**Brand baseline** — Baseline protocol storyboard — every brand agent must declare the brand protocol in capabilities and return a schema-valid brand identity.
Flow: `get_adcp_capabilities → get_brand_identity`
**Distributed brand.json mutual assertion resolves identity and relationship trust** — Consumer-under-test storyboard for AdCP 3.1 distributed brand.json: a house portfolio points at a child Brand Canonical Document, the child points back with house_domain, mutual assertion unlocks relationship trust, one-sided claims do not, identity stays brand-authored, compliance merges strictest-of, managed_by is directory metadata, and typed trademarks validate at the static-file layer.
Flow: `comply_test_controller`
**Partners MUST NOT extend trust on a single signed verify_brand_claim response** — Red conformance test for the asymmetric trust model on verify_brand_claim. A partner that auto-provisions, propagates governance, or otherwise extends relationship trust on the strength of one signed `owned` response fails — assertion direction requires reciprocation.
Flow: `comply_test_controller → verify_brand_claim → comply_test_controller → verify_brand_claim → comply_test_controller → verify_brand_claim`
**Brand agent rejects rights acquisition when governance denies** — Verifies that a brand agent propagates GOVERNANCE_DENIED when the buyer's governance plan denies a rights license.
Flow: `sync_plans → sync_accounts → sync_governance → get_rights → acquire_rights`
### Creative
**Creative lifecycle** — Baseline creative lifecycle on a stateful platform: sync display creatives, list with filtering, and preview renderings.
Flow: `get_adcp_capabilities → list_creative_formats → sync_creatives → list_creatives → preview_creative`