> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adcontextprotocol.org/llms.txt
> Use this file to discover all available pages before exploring further.

# S1: Media buy mastery

> AdCP specialist module S1: Media buy mastery. Full transaction lifecycle, pricing models, proposals, forecasting, and multi-agent orchestration with live sandbox agents.

# S1: Media buy mastery

<Info>
  **Members only** — Requires Practitioner credential. \~45 minutes with Addie.
  Combines hands-on lab and adaptive exam.
</Info>

This specialist module tests your mastery of the media buy transaction lifecycle. You'll work with live sandbox agents to execute complex flows: proposals, forecasting, refinement, packages, and multi-agent orchestration. Addie evaluates both your hands-on work and your conceptual understanding.

Passing earns the **AdCP specialist — Media buy** credential.

## Specialisms this track prepares you to validate

Agents in the `media_buy` domain declare specific flows they support via the `specialisms` field on `get_adcp_capabilities`. Each specialism has a compliance storyboard at `/compliance/{version}/specialisms/{id}/` that a runner executes to verify the claim. This module prepares you to reason about and validate agents against these claims:

| Specialism             | Status     | What it covers                                                                                 |
| ---------------------- | ---------- | ---------------------------------------------------------------------------------------------- |
| `sales-guaranteed`     | stable     | Guaranteed media buys with human IO approval                                                   |
| `sales-non-guaranteed` | stable     | Non-guaranteed auction-based media buys                                                        |
| `sales-proposal-mode`  | deprecated | **Deprecated in 3.1.** Replace with `sales-guaranteed` + `media_buy.supports_proposals: true`. |
| `sales-catalog-driven` | stable     | Catalog-driven commerce with conversion tracking                                               |
| `sales-broadcast-tv`   | stable     | Broadcast linear TV with guaranteed inventory and FCC cancellation rules                       |
| `sales-social`         | stable     | Social media advertising platform with self-service flows                                      |

See the [Compliance Catalog](/dist/docs/3.2.0-beta.0/building/verification/compliance-catalog) for the full taxonomy and the [`specialism` enum](https://adcontextprotocol.org/schemas/3.2.0-beta.0/enums/specialism.json) for the authoritative list.

## What you'll demonstrate

* Execute the full media buy lifecycle including proposals and forecasting
* Explain why every mutating media-buy request is cryptographically signed (RFC 9421): the signature is what lets the seller authenticate the buyer and detect tampering. No amount of lifecycle logic matters if you can't trust who sent the request.
* Walk the buyer-identity resolution chain: signature → JWKS → agent entry → brand.json. Explain why `iss` claims and client-supplied headers are never treated as identity, and what each link in the chain defends against.
* Apply `idempotency_key` correctly across the lifecycle: fresh UUID v4 per logical buy, same key + same payload on network retry (returns `replayed: true`), new key when the agent re-plans with a different payload, and the handling of `IDEMPOTENCY_CONFLICT` and `IDEMPOTENCY_EXPIRED`. Explain why this is what makes agent retries safe for real money.
* Trace the state machine: `create_media_buy` returns `pending_creatives` or `pending_start`; `sync_creatives` clears `pending_creatives`; the seller MUST transition `pending_start` → `active` at flight start and webhook the orchestrator. Seller-initiated `rejected` is only valid from the pending states.
* Reason about which actions are valid in which states (`cancel`, `sync_creatives` from pending states; `pause`/`resume`/`update_media_buy` from `active`), and handle `NOT_CANCELLABLE` and concurrency conflicts via `revision`
* Select a `pricing_option_id` from a product's `pricing_options[]` array — CPM, vCPM, CPP, CPA, flat rate, time — and explain why different pricing models carry different `parameters`
* Negotiate `measurement_terms` and `performance_standards` on guaranteed buys: propose overrides on `create_media_buy`, interpret seller acceptance (echoed back), adjustments, or `TERMS_REJECTED`. Recover by aligning to the seller's supported vendors or accepting product defaults.
* Know that `update_media_buy` requires `account` (not just `media_buy_id`) so billing routes to the right relationship; omitting it is a protocol error
* Tie broadcast buys to agency billing by attaching `agency_estimate_number` at the buy or package level (package-level overrides buy-level when flights or stations differ)
* Interpret broadcast delivery reports: `get_media_buy_delivery` returns measurement window data (`live`, `c3`, `c7`) that progresses over days after broadcast — the C7 window's DVR accumulation doesn't close until seven days post-air, and vendor processing adds further delay before final data is available; incomplete data during this period is by design, not underdelivery
* Use `get_media_buys` to check status, `valid_actions`, and creative approvals before acting
* Interpret seller indicators as current relationship-scoped state: explain why creative fatigue belongs to one package–creative assignment, why the same creative may be fatigued on one seller but not another, and why provider methodology belongs in `ext`
* Handle pricing negotiation, budget allocation, and multi-agent orchestration
* Use refinement and package requests for complex buying scenarios
* Monitor and optimize campaign delivery using protocol tools
* Explain the measurement-agent loop: make the orchestrator a buyer-controlled gateway for the fixed `get_media_buy_delivery` and `provide_performance_feedback` tasks, authenticate provider output, and fan normalized assertions out to sellers without granting providers seller access
* Reason about failure modes, conflict resolution, and edge cases

## Prerequisite reading

### Core transaction tasks

<CardGroup cols={2}>
  <Card title="get_products" icon="magnifying-glass" href="/dist/docs/3.2.0-beta.0/media-buy/task-reference/get_products">
    Product discovery: natural language briefs, structured filters, response
    schemas.
  </Card>

  <Card title="create_media_buy" icon="receipt" href="/dist/docs/3.2.0-beta.0/media-buy/task-reference/create_media_buy">
    Campaign creation: manual mode, proposal mode, approval lifecycle.
  </Card>

  <Card title="update_media_buy" icon="pen-to-square" href="/dist/docs/3.2.0-beta.0/media-buy/task-reference/update_media_buy">
    Campaign modification: budgets, targeting, scheduling, creative swaps.
  </Card>

  <Card title="get_media_buys" icon="list-check" href="/dist/docs/3.2.0-beta.0/media-buy/task-reference/get_media_buys">
    Operational status: lifecycle state, creative approvals, valid actions,
    delivery snapshots.
  </Card>

  <Card title="get_media_buy_delivery" icon="chart-line" href="/dist/docs/3.2.0-beta.0/media-buy/task-reference/get_media_buy_delivery">
    Delivery reporting: impressions, spend, completion rates, performance.
  </Card>
</CardGroup>

### Supporting concepts

<CardGroup cols={2}>
  <Card title="Media buy specification" icon="scroll" href="/dist/docs/3.2.0-beta.0/media-buy/specification">
    The formal specification for the media buy protocol.
  </Card>

  <Card title="Pricing models" icon="tag" href="/dist/docs/3.2.0-beta.0/media-buy/advanced-topics/pricing-models">
    `pricing_options[]` and `pricing_option_id`: CPM, vCPM, CPP, CPA, flat rate,
    time.
  </Card>

  <Card title="Accountability terms" icon="handshake" href="/dist/docs/3.2.0-beta.0/media-buy/advanced-topics/accountability">
    Negotiate `performance_standards`, `measurement_terms`, and
    `cancellation_policy`. Recovery from `TERMS_REJECTED`.
  </Card>

  <Card title="Proposal negotiation guide" icon="handshake" href="/dist/docs/3.2.0-beta.0/media-buy/product-discovery/proposal-negotiation">
    Typed constraints, ask-only fallback, immutable successors, holds, and
    acceptance.
  </Card>

  <Card title="Media buys overview" icon="layer-group" href="/dist/docs/3.2.0-beta.0/media-buy/media-buys/index">
    Campaign structure, the `pending_creatives` → `pending_start` → `active`
    state machine, and the approval lifecycle.
  </Card>

  <Card title="Indicators" icon="lightbulb" href="/dist/docs/3.2.0-beta.0/media-buy/media-buys/indicators">
    Seller interpretations such as package-scoped creative fatigue, returned through existing resource reads.
  </Card>

  <Card title="Trusted Match Protocol" icon="microchip" href="/dist/docs/3.2.0-beta.0/trusted-match">
    How TMP handles impression-time decisions such as cross-publisher frequency
    capping.
  </Card>

  <Card title="AdCP and OpenRTB" icon="arrows-left-right" href="/dist/docs/3.2.0-beta.0/building/concepts/adcp-vs-openrtb">
    How campaign workflows in AdCP connect to impression-time execution
    patterns.
  </Card>

  <Card title="Orchestrator design" icon="diagram-project" href="/dist/docs/3.2.0-beta.0/building/operating/orchestrator-design">
    Architecture patterns for multi-agent orchestration.
  </Card>

  <Card title="Conversion tracking" icon="bullseye" href="/dist/docs/3.2.0-beta.0/media-buy/conversion-tracking/index">
    Event sources, log\_event, and attribution setup.
  </Card>

  <Card title="Performance feedback" icon="comment-dots" href="/dist/docs/3.2.0-beta.0/media-buy/task-reference/provide_performance_feedback">
    Seller optimization feedback based on campaign performance.
  </Card>

  <Card title="Context and Identity Match" icon="arrows-split-up-and-left" href="/dist/docs/3.2.0-beta.0/trusted-match/context-and-identity">
    The two structurally separated operations that power impression-time
    execution.
  </Card>

  <Card title="Router architecture" icon="diagram-project" href="/dist/docs/3.2.0-beta.0/trusted-match/router-architecture">
    Deployment, fan-out, and provider configuration for the TMP Router.
  </Card>
</CardGroup>

## Connecting to the test agent

Lab exercises run against the public test agent. Use the shared token — no signup required:

```bash theme={null}
export ADCP_AUTH_TOKEN="1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ"
export AGENT_URL="https://test-agent.adcontextprotocol.org/sales/mcp"
```

See the [Quickstart](/dist/docs/3.2.0-beta.0/quickstart) for a walkthrough of your first call.

## Lab exercises

During the module, Addie will guide you through hands-on exercises:

1. **Product discovery and evaluation** — Query multiple sandbox agents, compare products, evaluate pricing
2. **Pricing option selection** — From the same product's `pricing_options[]` array, select a CPM option and a CPP option. Explain what each option's `parameters` mean and why the minimum spend differs.
3. **Proposal and forecasting** — Request proposals, analyze delivery forecasts (spend curves and availability)
4. **Terms negotiation** — On a guaranteed product, propose `measurement_terms` with a different vendor than the seller's default, and `performance_standards` with a tighter viewability threshold. Observe seller acceptance, adjustment, or `TERMS_REJECTED`. Recover by aligning to the seller's supported vendors.
5. **Campaign commitment and optimization** — Commit a direct offer with `buy_products`, assign creatives through `sync_creatives`, monitor through `get_media_buys`, and apply an in-envelope change with `control_media_buy`. Submit compact performance feedback with a named baseline, interpreting `accepted`, `applied`, and `not_applied` without overstating causality. Explain how the 3.x `create_media_buy` and `update_media_buy` facades map to the canonical operations, and verify that the update facade requires `account`.
6. **Proposal negotiation and lifecycle walkthrough** — Following the [proposal negotiation implementation guide](/dist/docs/3.2.0-beta.0/media-buy/product-discovery/proposal-negotiation), act as Sam at Pinnacle Agency against StreamHaus. Use `request_proposals`, inspect `proposal_refinement.supported_dimensions`, and construct a refinement the seller can actually evaluate. Try a USD budget ceiling, a product include/omit decision, a targeting change, and multiple alternatives only when advertised; interpret `partial` and `unable` as structured counteroffers rather than generic failures. On an ask-only seller, observe the pre-mutation `UNSUPPORTED_FEATURE`, remove or translate the typed field, and retry. Finalize the chosen immutable proposal, call `accept_proposal`, and trace the resulting buy through `pending_creatives` → `sync_creatives` → `pending_start` → `active`.
7. **Lifecycle management and recovery** — Use `revision` for concurrency, follow `available_actions` to `control_media_buy` for operational changes, and route commercial changes through `refine_proposals(accepted_proposal_id)` plus `accept_proposal`. Handle `REQUOTE_REQUIRED` without mutating the accepted snapshot.
8. **Broadcast billing and delivery** — Create a broadcast buy with a buy-level `agency_estimate_number` and one package that overrides it with a station-specific estimate number. Verify both appear on delivery reconciliation. Call `get_media_buy_delivery` and interpret the measurement window fields: explain why `c3` data may be incomplete immediately after broadcast and when the `c7` window closes.
9. **Multi-agent orchestration and execution** — Manage campaigns across multiple sellers. Trace a cross-publisher suppression scenario: a viewer sees an ad on publisher A, then visits publisher B within the 2-hour recency window — what does Identity Match return and why? Configure frequency parameters (5/week, 2-hour minimum recency) and predict delivery impact. Explain why Context Match and Identity Match are structurally separated. Then design, conceptually and outside the public sales-agent sandbox, an orchestrator-hosted measurement gateway that exposes `get_media_buy_delivery` and `provide_performance_feedback`, grants only those orchestrator tasks, and maps one cross-seller result into seller-local submissions.
10. **Warnings, indicators, and invalidations** — Analyze a success warning and the later resource snapshot; distinguish buy/package/assignment indicator placement, exact type coverage, assignment approval, and webhook invalidation handling.

For the indicator exercise, Addie supplies this compact creative-library fixture:

```json theme={null}
{
  "creative_id": "acme_summer_video",
  "assignments": {
    "assignment_count": 3,
    "returned_assignment_count": 3,
    "assignments_truncated": false,
    "assigned_packages": [
      {
        "media_buy_id": "mb_a",
        "package_id": "pkg_social",
        "assigned_date": "2026-08-01T00:00:00Z",
        "approval_status": "approved",
        "indicator_types_evaluated": [
          "creative_fatigue",
          "creative_quality_opportunity"
        ],
        "indicators_as_of": "2026-08-04T12:00:00Z",
        "indicators_evaluated_scope": [
          { "publisher_domain": "publisher-a.example" }
        ],
        "indicators": [
          {
            "type": "creative_fatigue",
            "scope": [
              {
                "publisher_domain": "publisher-a.example",
                "placement_id": "feed"
              }
            ]
          }
        ]
      },
      {
        "media_buy_id": "mb_b",
        "package_id": "pkg_social",
        "assigned_date": "2026-08-01T00:00:00Z",
        "approval_status": "approved",
        "indicator_types_evaluated": ["creative_fatigue"],
        "indicators_as_of": "2026-08-04T12:00:00Z",
        "indicators": []
      },
      {
        "media_buy_id": "mb_c",
        "package_id": "pkg_social",
        "assigned_date": "2026-08-01T00:00:00Z",
        "approval_status": "pending_review"
      }
    ]
  }
}
```

The learner must identify the first relationship as evaluated for two creative types only on publisher A, with fatigue asserted only on its feed placement. The second is clear only for fatigue, not for every indicator type. The third is unknown but still has stable relationship identity and approval state. Clearing requires a direct, covered, strictly newer snapshot.

Addie then supplies this successful `control_media_buy` receipt:

```json theme={null}
{
  "status": "completed",
  "media_buy_id": "mb_a",
  "revision": 2,
  "warnings": [
    {
      "code": "inventory_shortfall_forecast",
      "message": "The applied pacing control leaves forecast delivery below the requested goal.",
      "affected_resource": {
        "resource_type": "package",
        "media_buy_id": "mb_a",
        "package_id": "pkg_social"
      }
    }
  ]
}
```

The learner must explain that the control succeeded and the warning is only its immediate receipt. A subsequent unfiltered `get_media_buys` read supplies the durable conclusion. The same warning may be mirrored by the `update_media_buy` compatibility facade:

```json theme={null}
{
  "status": "completed",
  "media_buys": [
    {
      "media_buy_id": "mb_a",
      "status": "active",
      "currency": "USD",
      "total_budget": 10000,
      "confirmed_at": "2026-08-01T00:00:00Z",
      "revision": 2,
      "packages": [
        {
          "package_id": "pkg_social",
          "indicator_types_evaluated": ["inventory_shortfall_forecast"],
          "indicators_as_of": "2026-08-04T12:00:00Z",
          "indicators": [{ "type": "inventory_shortfall_forecast" }]
        }
      ]
    }
  ],
  "pagination": { "has_more": false }
}
```

The learner must reject treating the warning as either an error or durable state.

Finally, after activating the subscriber and establishing a complete `get_media_buys` baseline (known IDs or every status, fully paginated, without `indicator_types`), the learner receives these invalidations in either order:

```json theme={null}
{
  "idempotency_key": "whk_01K2INDICATOR4EXAMPLE8Q7M5",
  "notification_id": "indchg_1",
  "notification_type": "indicators.changed",
  "fired_at": "2026-08-04T12:01:00Z",
  "subscriber_id": "optimization-worker",
  "account_id": "acc_1",
  "relationship_kind": "creative_assignment",
  "media_buy_id": "mb_a",
  "package_id": "pkg_social",
  "creative_id": "acme_summer_video",
  "change_kind": "cleared",
  "changed_indicator_types": ["creative_fatigue"],
  "observed_at": "2026-08-04T12:00:00Z"
}
```

```json theme={null}
{
  "idempotency_key": "whk_01K2ASSIGNMENT4EXAMPLE9R6",
  "notification_id": "assignchg_1",
  "notification_type": "creative.assignment_changed",
  "fired_at": "2026-08-04T12:01:00Z",
  "subscriber_id": "optimization-worker",
  "account_id": "acc_1",
  "media_buy_id": "mb_a",
  "package_id": "pkg_social",
  "creative_id": "acme_summer_video",
  "change_kind": "approval_changed",
  "observed_at": "2026-08-04T12:00:00Z"
}
```

The learner describes the required signature-verification step, dedupes each fire, coalesces them into one unfiltered reread, and reconciles only from the returned snapshot. Cryptographic execution is out of scope for this module; implementers follow the [webhook callback verifier checklist](/dist/docs/3.2.0-beta.0/building/by-layer/L1/security#webhook-callbacks). A timestamp-only reevaluation must not fire. Assignment removal retires prior keys even when the two invalidations arrive in either order.

For a generative assignment, the learner must explain that this indicator describes the stable brief-or-creative × package aggregate. Fatigue for individual live renders belongs in `get_creative_delivery`. A material in-place brief revision invalidates the prior evaluation and fires `indicators.changed`; the snapshot is unknown until reevaluated. After replacing the creative, a successful direct unfiltered read confirming the old assignment is absent retires its old indicator keys; filtered disappearance does not.

## Assessment

| Dimension           | Weight | What Addie evaluates                               |
| ------------------- | ------ | -------------------------------------------------- |
| Protocol mastery    | 30%    | Comprehensive understanding of media buy lifecycle |
| Targeting expertise | 25%    | Masters advanced targeting capabilities            |
| Analytical skill    | 25%    | Analyzes delivery data effectively                 |
| Problem solving     | 20%    | Handles complex scenarios and edge cases           |

Passing threshold: 70%.

## Start this module

<Card title="Start S1 with Addie" icon="play" href="https://agenticadvertising.org/chat">
  "I'd like to start the media buy specialist module."
</Card>
