> ## 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.

# Indicators and Warnings

> How AdCP exposes immediate operation warnings and durable seller indicators through existing media-buy and creative reads.

AdCP separates an immediate successful-operation warning from a condition that remains current after the operation:

| Situation                                                                                        | Protocol surface                                           |
| ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
| Operation failed                                                                                 | `errors[]`                                                 |
| Operation needs buyer input before success                                                       | `input-required`                                           |
| Operation succeeded with noteworthy context                                                      | `warnings[]` on the success response                       |
| Seller identifies a current material risk or optimization opportunity warranting buyer attention | `indicators[]` on the authoritative read                   |
| Creative is approved, partially approved, pending, or rejected for one assignment                | Assignment approval state and optional `approval_scopes[]` |
| Resource is serving with a quality or coverage gap                                               | Resource defect surface                                    |
| Buy/package cannot deliver correctly                                                             | Impairment or operational delivery issue                   |

A warning is an immediate receipt. It MUST NOT become the only home for a continuing condition: a persistent forecast, pacing, creative, or budget conclusion also appears as current resource state. An indicator is not a separate resource—there is no indicator ID, history API, sub-version, or `get_indicators` task.

An indicator says that the buyer should evaluate and probably address a condition. It does not claim that one universal remedy exists, authorize a mutation, or make seller-supplied text executable. Buyer products may translate an indicator into one or more recommendations, but any resulting change still uses its normal AdCP task, authorization, and governance path.

## Where indicators live

`get_media_buys` carries three levels of current indicator state:

```text theme={null}
media_buys[]                            buy indicators
└── packages[]                         package indicators
    └── creative_approvals[]           assignment indicators
```

Creative-library sellers may expose the same package–creative relationship in reverse:

```text theme={null}
creatives[]
└── assignments.assigned_packages[]   assignment approval + indicators
```

When `media_buy.relationship_notifications.projection_tasks` includes `list_creatives`, the two assignment projections MUST agree on `media_buy_id`, `package_id`, `creative_id`, approval state, rejection reason, and scoped approval outcomes. Indicator state SHOULD converge, but separate reads can legitimately straddle a reevaluation; buyers reconcile toward the snapshot with the strictly newer `indicators_as_of`. The seller includes `media_buy_id` and `approval_status` on every creative assignment row, even when indicators are unknown. Inline-only sellers use `get_media_buys` without implementing this reverse projection.

Do not put assignment-specific fatigue or approval on the creative root. One creative can be fatigued or rejected on one publisher while remaining effective and approved elsewhere. When a multi-publisher assignment has mixed eligibility, the scalar is `partially_approved` and complete `approval_scopes[]` carries a disjoint partition: one row per normalized scope, using either publisher-wide or placement-specific rows for a publisher, never both. Uniform assignments omit the array.

## Standard 3.2 catalog

| Type                           | Valid placement             | Broad meaning                                                                                                   |
| ------------------------------ | --------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `creative_fatigue`             | Package–creative assignment | Repeated delivery is materially saturating the audience or degrading objective-relevant performance             |
| `creative_quality_opportunity` | Package–creative assignment | The accepted creative has a material format, asset, composition, or quality improvement opportunity             |
| `creative_diversity_low`       | Package                     | Too few meaningfully distinct eligible creatives for effective rotation, learning, reach, or fatigue resistance |
| `audience_saturation`          | Package                     | The reachable audience is materially saturated independent of one creative                                      |
| `inventory_shortfall_forecast` | Package                     | Current forecast is materially below the requested delivery goal                                                |
| `pacing_risk`                  | Package                     | Material over- or under-delivery is projected by flight end absent intervention                                 |
| `budget_constrained`           | Media buy or package        | Budget or a spend cap materially limits otherwise eligible delivery                                             |

The negotiated AdCP release defines these broad meanings, not a universal algorithm. Provider scores, thresholds, evaluation windows, native labels, suggested actions, deep links, and upstream attribution remain in namespaced `ext`. A generic action dispatcher is intentionally absent; applying a recommendation still uses normal AdCP authorization, governance, idempotency, and readback.

## Evaluated snapshot shape

```json theme={null}
{
  "creative_id": "cr_summer_video",
  "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",
      "detected_at": "2026-08-03T09:00:00Z",
      "scope": [
        {
          "publisher_domain": "publisher-a.example",
          "placement_id": "feed"
        }
      ],
      "ext": {
        "seller_example": {
          "fatigue_rate": 0.47,
          "window_days": 7
        }
      }
    }
  ]
}
```

`indicator_types_evaluated` is required with `indicators`. It prevents an empty fatigue result from being misread as an evaluation of pacing, budget, or another type. Every returned `indicator.type` MUST appear in this list; omitted types remain unknown.

`indicators_as_of` records when this evaluation completed. `indicators_evaluated_scope` optionally limits publisher or placement coverage. Omit scope coverage only when the named types were evaluated across the whole enclosing buy, package, or assignment. With partial coverage, every indicator includes a contained `scope`; unlisted scopes remain unknown.

Only `type` is required inside each indicator. `detected_at`, when known, remains stable throughout one uninterrupted occurrence. A relationship contains at most one item per `(type, normalized scope set)`.

## Unknown, clear, and monotonic state

* Omitted `indicators` means unknown or not evaluated.
* `indicators: []` means evaluated-clear only for `indicator_types_evaluated` and the declared coverage.
* A non-empty array is the current assertion set for those types and coverage.
* A prior key clears only when absent from a successful direct snapshot with coverage containing the key and a strictly newer `indicators_as_of`.
* Equal-timestamp conflicting snapshots are invalid; buyers retain stored state.
* Filtered disappearance, incomplete pagination, a failed read, or uncovered scope never clears state.
* A successful direct unfiltered read showing that an assignment was deleted retires all keys for that relationship.

For serve-time generative creative, assignment indicators describe the stable brief-or-creative × package aggregate. Variant/render diagnostics belong in `get_creative_delivery`.

## Querying

Use `list_creatives` for portfolio-wide assignment indicator discovery:

```json theme={null}
{
  "include_assignments": true,
  "filters": {
    "indicator_types": ["creative_fatigue", "creative_quality_opportunity"]
  },
  "fields": ["creative_id", "assignments"],
  "pagination": {
    "max_results": 100
  }
}
```

The outer cursor limits creatives. For bounded portfolio discovery, request `assignment_projection: "matching"` and `assignment_limit`; each result reports `returned_assignment_count` and `assignments_truncated`. A truncated reverse projection is discovery-only—repair complete state through `get_media_buys`. Reread known relationships without `indicator_types` when reconciling clearing.

`get_media_buys.indicator_types` matches an indicator at any of the three levels and returns the selected full buy. Use it for buy/package conclusions such as budget, inventory, audience, diversity, or pacing. Buyers MUST NOT send the filter unless every requested type appears in `supported_indicator_types`; a seller MAY reject a violation with `UNSUPPORTED_FEATURE`. This avoids an undetectable unfiltered superset on a response that has no `filters_applied` receipt.

## Webhooks

`supported_indicator_types` declares polling readback independently of webhook support. A seller may expose indicators through `get_media_buys` and omit `relationship_notifications` entirely. Sellers that support push additionally declare `media_buy.relationship_notifications`; `indicators.changed` requires an indicator catalog, while `creative.assignment_changed` may be declared alone when the seller can detect assignment or approval changes. A creative-library seller may advertise the bounded `list_creatives` reverse projection inside that block. The capability also declares whether activity logs are available:

```json theme={null}
{
  "subscriber_id": "optimization-worker",
  "url": "https://buyer.example/webhooks/adcp",
  "event_types": [
    "indicators.changed",
    "creative.assignment_changed"
  ],
  "active": true
}
```

`indicators.changed` fires after the seller observes a semantic assertion-set or evaluation-coverage change. It does not fire because only `indicators_as_of` advanced. `creative.assignment_changed` fires when an assignment is added, removed, or its assignment-specific approval state/reason changes. Removing an assignment with stored indicators also fires `indicators.changed` with `change_kind: "assignment_removed"`; the two fires have no ordering guarantee.

Subscriptions are prospective and do not replay already-current indicators. After activation or reactivation, establish a complete baseline through `get_media_buys`: either enumerate known `media_buy_ids`, or request all seven `status_filter` values and follow pagination to exhaustion. Do not use `indicator_types` for this baseline. A material in-place creative-content update retires the prior assignment evaluation: the seller fires `indicators.changed` with `change_kind: "invalidated"` and omits the stale snapshot as unknown until reevaluated, or atomically publishes a strictly newer evaluation and fires `updated`.

Both payloads are small signed invalidations containing account, media-buy, package, and—when applicable—creative identity. Buyers:

1. verify the registered webhook signature;
2. dedupe by `idempotency_key`;
3. reread `get_media_buys` without an indicator filter (the bounded `list_creatives` projection may assist discovery but cannot prove complete state); and
4. reconcile from the snapshot, never from the webhook payload.

Retries reuse the same `idempotency_key`. Poll-based upstream integrations fire when they detect a change; capability support does not promise native-platform detection latency. Relevant delivery attempts appear on the declared repair reads when `supports_webhook_activity` is true and activity was requested.

## Success warnings

Completed `buy_products` and `accept_proposal` commitments and completed `control_media_buy` controls may return structured `warnings[]`. The 3.x `create_media_buy` and `update_media_buy` compatibility facades mirror the warning returned by the canonical operation they map to. Proposal planning (`request_proposals` and `refine_proposals`) carries forecasts in proposal state rather than using commitment warnings. Initial codes are:

| Code                                | Typical durable readback                                                                 |
| ----------------------------------- | ---------------------------------------------------------------------------------------- |
| `inventory_shortfall_forecast`      | Package indicator of the same name                                                       |
| `flight_change_creates_pacing_risk` | Package `pacing_risk`                                                                    |
| `fields_ignored_due_to_precedence`  | Operation-relative receipt; no continuing condition. `details` identifies ignored fields |

Canonical commitments use the first two codes: direct or newly accepted purchases may report `inventory_shortfall_forecast`, and an accepted flight amendment may report `flight_change_creates_pacing_risk`. `control_media_buy` does not change flight dates and therefore only uses `inventory_shortfall_forecast` from this initial catalog. `fields_ignored_due_to_precedence` remains a compatibility-facade receipt; canonical inputs reject conflicting intent instead of silently applying legacy precedence.

Every warning includes typed `affected_resource` identity so buyers can join it to durable state in multi-package and multi-creative responses. On compact commitment responses, package IDs come from `purchase_bindings[]`. Warnings never change success, never appear on terminal or submitted arms, and never grant action authority. Codes are the closed vocabulary of the negotiated AdCP release. `details` is seller-specific in 3.2; portable handling relies only on `code` and `affected_resource`. Whether `inventory_shortfall_forecast` surfaces as a warning on a completed commitment or instead blocks via `input-required` is seller discretion; a buyer unconditionally carries delivery risk on a MediaBuy committed with that warning.

A seller MUST NOT emit `inventory_shortfall_forecast` unless it advertises that indicator type, or `flight_change_creates_pacing_risk` unless it advertises `pacing_risk`. This keeps the promised durable readback available; `fields_ignored_due_to_precedence` is operation-relative and needs no indicator capability.
