Skip to main content

Documentation Index

Fetch the complete documentation index at: https://agenticadvertisingorg-changeset-release-main.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

If you’re building the buy side — a DSP, planning tool, agentic client, or any application that calls AdCP agents to plan, buy, and report — start here. Caller-side L0–L3 is weeks of handler glue, not the 3–4 person-month build the agent side requires. The full-stack SDK in your language carries L0–L3; you write the calling logic, response handling, and whatever your application does with the data.
Spec-level reference vs build-shaped guide. This page walks you through the build. The wire-level invariants — every rule that applies to every mutating call — live at Calling an AdCP agent. Read it once before going to production; refer back whenever you’re debugging a wire-shape error.
Try it against a live agent. AAO runs a public test agent at https://test-agent.adcontextprotocol.org with per-domain endpoints — /sales/mcp, /creative/mcp, /signals/mcp, /governance/mcp. Point your client at the matching endpoint and getAdcpCapabilities() works without auth. Use it to verify your install before pointing at a real seller.

Install the SDK

The same SDKs that ship server primitives also ship the calling client. Install one and you have both.
npm install @adcp/sdk
import { createSingleAgentClient } from '@adcp/sdk';

const client = createSingleAgentClient({
  id: 'sales',
  name: 'Sales agent',
  agent_uri: 'https://sales.example.com/mcp',
  protocol: 'mcp',
});
For multi-agent fan-out (one client driving many sellers in parallel) use ADCPMultiAgentClient instead — same call surface, indexed by agent id.

Authenticate

Most agents require credentials before they’ll respond to anything beyond get_adcp_capabilities. The SDK accepts auth at construction:
const client = createSingleAgentClient({
  id: 'sales',
  name: 'Sales agent',
  agent_uri: 'https://sales.example.com/mcp',
  protocol: 'mcp',
  auth_token: process.env.ADCP_API_KEY,
});
If your first call returns a 401 / AUTH_REQUIRED, the credentials aren’t reaching the agent — check the constructor option, not the request payload. See the L1 security implementation profile for the full credential model.

First call: discover the agent

Before calling tools by hand, ask the agent what it supports.
const capabilities = await client.getAdcpCapabilities();
// → { supported_protocols: [...], adcp_versions: [...], features: {...} }
get_adcp_capabilities returns the agent’s protocol coverage, AdCP version range, and feature flags. Use it to gate calls — if media_buy isn’t in supported_protocols, don’t call create_media_buy against this agent. See the get_adcp_capabilities reference for the full response shape. For the rest of the discovery chain (agent card, tools/list, get_schema), see the Discovery chain section of Calling an agent.

Make a call

Typed methods on the client correspond to AdCP tools. The SDK validates your request against the bundled schemas before sending and parses the response into a typed value.
const products = await client.getProducts({
  brief: 'Video campaign for pet owners, 18–34, US, $50K monthly',
});

const buy = await client.createMediaBuy({
  idempotency_key: crypto.randomUUID(),
  account: { brand: { domain: 'acme.com' }, operator: 'sales.example' },
  packages: [/* … */],
});
Two things worth knowing on the first call:
  • Generate a fresh idempotency_key per logical operation. Same key on retry → server replays the same response. Fresh key after a failure creates duplicate buys. See the Idempotency rules.
  • account is a discriminated oneOf. Pick one variant ({account_id} from sync_accounts / list_accounts, or {brand, operator} as the natural key — brand.domain is the buyer’s brand domain, operator is the seller agent’s deployment hostname or brand.json identifier) and send only its required fields. Merging them fails both. See account is oneOf.

Handle the three response shapes

Every mutating tool returns one of three shapes. Handle them explicitly.
const response = await client.createMediaBuy({/* … */});

if ('errors' in response) {
  // Error: don't retry without fixing — read response.adcp_error.issues[]
  // for correctable failures (validation, oneOf, etc.)
} else if (response.status === 'submitted') {
  // Async: the work is queued, NOT done. The completion payload arrives
  // later — either via webhook (preferred) or by polling tasks/get.
} else {
  // Sync success: response carries the completion payload directly.
  // (e.g., response.media_buy_id, response.packages)
}
The SDK steers you to webhooks for async completion. Configure webhookUrlTemplate and a status-change handler at construction; the SDK verifies the inbound webhook against the seller’s JWKS and fires your handler with the same result shape that synchronous responses carry — see Receive webhooks below. If you must poll instead of using webhooks (e.g. inside a one-shot script), call tasks/get directly via the underlying transport. The Async responses section of Calling an agent has the wire contract.

Recover from errors

When you see adcp_error in a response, read issues[] and act based on recovery:
const { code, recovery, issues } = response.adcp_error;

switch (recovery) {
  case 'correctable':
    // Buyer-side fix. Patch the JSON pointers from issues[], resend with
    // the SAME idempotency_key (fresh key = new operation).
    break;
  case 'transient':
    // Retry with the SAME idempotency_key. Same key on retry replays the
    // cached response if the work landed.
    break;
  case 'terminal':
    // Human action required. Don't retry.
    break;
}
issues[] is the actionable part: each entry has a JSON Pointer (pointer), an Ajv keyword (required, oneOf, enum, etc.), and — for oneOf failures — a variants[] array listing each variant’s required fields. See the Error recovery section for the full envelope and recovery semantics.

Receive webhooks

For async tasks, you can either poll or register a webhook. The webhook delivers the same result payload as a tasks/get with include_result: true. The SDK ships an RFC 9421 webhook verifier (createWebhookVerifier from @adcp/sdk/signing/server) that resolves keys via the seller’s brand.json, enforces the replay window, and surfaces structured errors for the webhook error taxonomy. If you wire the multi-agent client with a webhookUrlTemplate and status-change handlers (per the @adcp/sdk README), incoming webhooks are verified and dispatched into your handlers automatically — your HTTP route is one line that hands the request to the client. For the wire-level requirements your endpoint MUST satisfy regardless of how it’s wired (covered components, content-digest enforcement, dedup discipline), see L3 — Webhooks.

Ingest reporting

Reporting is read-only and follows the same call/response shape as everything else. Pull delivery for the buys you own and iterate on a windowed cadence:
const delivery = await client.getMediaBuyDelivery({
  media_buy_ids: ['mb_123', 'mb_456'],
  window: { start: '2026-05-01T00:00:00Z', end: '2026-05-02T00:00:00Z' },
});
For sellers that support performance webhooks, you’ll receive deltas via the same webhook receiver shown above; otherwise poll on whatever cadence your reporting needs. Caller L4 — optimization, pacing alerts, attribution joins, dashboards — is your application code on top of the typed delivery object.

What you didn’t have to write

Caller-side L0–L3 is weeks of handler glue because the SDK already shipped:
  • L0 — typed request builders, response parsers, schema validation against the bundled schemas.
  • L1 — outbound RFC 9421 signing (per-call), inbound webhook verification, key rotation.
  • L2 — agent registry lookup, agent-card publication, credential composition.
  • L3 — async-task polling, webhook receiver, idempotency-key generation helpers, error-recovery classification.
The SDK stack reference decomposes each layer; the server-vs-client comparison table is the side-by-side view of the cost asymmetry.

What’s next

  • Calling an agent — the canonical wire-contract reference. Read once before going to production.
  • Schemas — schema bundle, type generation, version pinning.
  • Webhooks — push notifications, signing, retry, reliability patterns.
  • Error handling — error categories, codes, recovery classification.
  • Validate your agent — storyboards also exist for caller-side wire conformance; run them once your calls are working.
Per-protocol task references: