{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://adcontextprotocol.org/schemas/3.2.0-beta.10/enums/notification-type.json",
  "title": "Notification Type",
  "description": "Type of push notification fired by a seller agent. Media-buy-anchored cadence reports (`scheduled`, `final`, `delayed`, `adjusted`, `window_update`) fire against a media buy's `reporting_webhook`; `impairment` is media-buy-anchored but fires against `push_notification_config`. Account-anchored notifications include creative, account, product, signal, wholesale-feed, and reporting events, including `reporting.delivery_ready` and `reporting.status_changed`; these outlive any single media buy and fire against matching account `notification_configs[]`. The reporting events repair through `get_reporting_status`: delivery_ready is managed-delivery-only, while status_changed is valid in every reporting tier. Caller-anchored notifications (`capabilities.changed`, `principal.changed`) fire against the caller-scoped subscriber set managed by `sync_principal` or the specialized `sync_agent_notification_configs` compatibility task. New notification types MUST declare their anchor (media-buy, account, or caller), logical notification_id semantics, repair key, and classification in enumDescriptions; only invalidation-only caller-eligible types flow through include_future_event_types. Account-level subscribers MUST reject media-buy- or caller-anchored event types, and persistent account- or caller-anchored types MUST NOT use push_notification_config. Caller-level entries MAY include account-anchored types only with all_authorized_accounts true; each delivery attempt, including retries, is scoped to accounts currently authorized for that caller. Caller-level entries MUST NOT include media-buy-anchored types. Caller- and account-level subscriptions to the same event are independent and receivers dedupe by logical notification_id.",
  "type": "string",
  "enum": [
    "scheduled",
    "final",
    "delayed",
    "adjusted",
    "window_update",
    "impairment",
    "creative.status_changed",
    "creative.assignment_changed",
    "indicators.changed",
    "creative.purged",
    "account.status_changed",
    "account.change_recorded",
    "product.created",
    "product.updated",
    "product.priced",
    "product.removed",
    "signal.created",
    "signal.updated",
    "signal.priced",
    "signal.removed",
    "wholesale_feed.bulk_change",
    "capabilities.changed",
    "reporting.delivery_ready",
    "reporting.status_changed",
    "principal.changed"
  ],
  "enumDescriptions": {
    "scheduled": "Scheduled delivery report fire. Fired at the cadence the buyer registered on reporting_webhook (e.g., hourly, daily). Carries the window's delivery metrics. **notification_id**: absent — point-in-time data event with no persistent state id (snapshot-and-log Rule 1). Dedupe by `idempotency_key` only.",
    "final": "Terminal delivery report fire. Sent once after the media buy reaches a terminal lifecycle state (completed, canceled, rejected). Carries final delivery aggregates. **notification_id**: absent — point-in-time data event with no persistent state id (snapshot-and-log Rule 1). Dedupe by `idempotency_key` only.",
    "delayed": "Off-cadence delivery report fire indicating that the seller has detected late-arriving data for a prior window. Buyers SHOULD reconcile the affected window against this fire. **notification_id**: absent — point-in-time data event with no persistent state id (snapshot-and-log Rule 1). Dedupe by `idempotency_key` only.",
    "adjusted": "Off-cadence delivery report fire indicating that the seller has revised a prior window's metrics (e.g., IVT filtering applied, attribution model run, makegood adjustment). Buyers SHOULD replace prior values for the affected window. **notification_id**: absent — point-in-time data event with no persistent state id (snapshot-and-log Rule 1). Dedupe by `idempotency_key` only.",
    "window_update": "Off-cadence delivery report fire indicating that a wider measurement window supersedes an earlier window for the same reporting period (for example, C3 superseding live or C7 superseding C3). Buyers SHOULD replace the slice named by `supersedes_window` with the new `measurement_window` data. **notification_id**: absent — point-in-time data event with no persistent state id (snapshot-and-log Rule 1). Dedupe by `idempotency_key` only.",
    "impairment": "Dependency state change fire. Sent when a resource referenced by the buy enters an offline state that affects delivery for at least one package. Payload carries the impairment object and the buy's updated health. See impairment.json and the impairment.coherence assertion. **notification_id**: equals `impairment.impairment_id`. Stable across re-emissions of the same open impairment and across the closing fire that signals resolution; a new impairment for the same resource after closure receives a new id.",
    "creative.status_changed": "Account-anchored fire. Sent when a creative in the account's library transitions status by seller or system initiative — `pending_review → approved`/`rejected`, `approved → pending_review` (re-review), `approved → suspended` (recoverable dependency/authorization loss), `suspended → approved` (recovery), `suspended → rejected` (terminal dependency/authorization loss), `approved → rejected` (post-approval revocation), `approved → archived` (seller-initiated). Fires per subscriber against each `notification_configs[]` entry whose `event_types` includes this value. Buyer-initiated transitions (archive, unarchive, resubmit) do NOT fire — those are acknowledged on the `sync_creatives` response path. Payload: `creative-status-changed-webhook.json`. **notification_id**: stable per (creative_id, transition) — re-emissions reuse the id; a fresh transition gets a new id.",
    "creative.assignment_changed": "Optional account-anchored invalidation for any seller that can detect assignment or approval changes, including inline-only sellers without an indicator catalog. Sent when a package–creative relationship is assigned, unassigned, or its aggregate/scoped approval outcome changes. Payload identifies account, media buy, package, and creative; receivers repair through get_media_buys. list_creatives may provide a bounded reverse projection but is not required. **notification_id**: stable per logical assignment change across re-emissions.",
    "indicators.changed": "Account-anchored invalidation. Sent to subscribed buyers when the semantic indicator assertion set or evaluated coverage changes on a media buy, package, or package–creative assignment, including invalidation after a material in-place creative update. A timestamp-only reevaluation does not fire. Payload identifies the relationship and affected types; get_media_buys is the universal repair path and creative-library sellers may additionally declare list_creatives. **notification_id**: stable per logical snapshot change across re-emissions.",
    "creative.purged": "Account-anchored fire. Sent when a creative is destroyed from the seller's library (retention sweep, takedown, legal erasure). Fires per subscriber against each `notification_configs[]` entry whose `event_types` includes this value. Soft purges retain a tombstone on `list_creatives` (with `include_purged: true`) for the webhook retention window and form a conformant snapshot/log pair. Hard purges do not retain a tombstone because compelled legal erasure forbids read-side recovery; they are explicitly outside the snapshot/log contract, and the webhook is the buyer's only signal. Payload: `creative-purged-webhook.json`. **notification_id**: stable per (creative_id, purge event); not coalesced (purge is a discrete destruction event).",
    "account.status_changed": "Account-anchored fire. Sent when an account lifecycle status changes after the initial sync_accounts result, including `pending_approval -> active`, `pending_approval -> rejected`, `active -> payment_required`, `active -> suspended`, recovery back to `active`, and terminal `closed`. Fires per subscriber against each `notification_configs[]` entry whose `event_types` includes this value. Payload: `account-status-changed-webhook.json`. The payload does not include the full account document or setup.url; receivers SHOULD re-run `list_accounts` for the account_id and reconcile from the authoritative account snapshot. **notification_id**: stable per (account_id, previous_status, status, observed_at) — re-emissions reuse the id; a fresh transition cycle receives a new id.",
    "account.change_recorded": "Account-anchored invalidation. Sent once per committed material change represented in `list_account_changes`, including changes made through AdCP, a seller operator or system, another authorized principal, or a connected platform. Payload: `account-change-recorded-webhook.json`. Receivers drain from their own persisted feed cursor and then call the change record's repair task; the webhook is not authoritative current state. **notification_id**: equals `change_id`. Transport retries reuse one `idempotency_key`; deliberate re-emission uses a new delivery key with the same notification_id.",
    "product.created": "Sent when a new product is added to the seller's wholesale product feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `product.created` event with the full post-change Product object. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "product.updated": "Sent when product metadata changes in the seller's wholesale product feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `product.updated` event with the changed Product object when available and indicator `changed_fields[]`. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "product.priced": "Sent when product pricing changes in the seller's wholesale product feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `product.priced` event with the full post-change `pricing_options[]`, optional retired pricing ids, and optional `effective_at`. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "product.removed": "Sent when a product is no longer available in the seller's wholesale product feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `product.removed` event with the product id, optional removal reason, and cache scope. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "signal.created": "Sent when a new signal is added to the seller's wholesale signals feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `signal.created` event with the post-change signal identifiers and available metadata. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "signal.updated": "Sent when signal metadata changes in the seller's wholesale signals feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `signal.updated` event with the changed signal data when available and indicator `changed_fields[]`. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "signal.priced": "Sent when signal pricing changes in the seller's wholesale signals feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `signal.priced` event with the full post-change `pricing_options[]`, optional retired pricing ids, and optional `effective_at`. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "signal.removed": "Sent when a signal is no longer available in the seller's wholesale signals feed for the subscriber's account scope. Payload: `wholesale-feed-webhook.json` carrying a `signal.removed` event with the signal id, optional removal reason, and cache scope. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "wholesale_feed.bulk_change": "Sent when one operation changes too many wholesale product-feed or wholesale signals-feed entities for useful per-entity pushes. Payload: `wholesale-feed-webhook.json` carrying a `wholesale_feed.bulk_change` event with one affected entity type, approximate count, and repair recommendation. Receivers repair products through `list_products` (or deprecated 3.x `get_products`) and signals through `get_signals`. **notification_id**: equals `event.event_id`; re-emissions of the same logical change reuse the same value under a new `idempotency_key`.",
    "capabilities.changed": "Agent-anchored fire. Sent when the seller's advertised `get_adcp_capabilities` document materially changes. Fires per subscriber against each caller-scoped agent `notification_configs[]` entry managed through `sync_principal` or `sync_agent_notification_configs` whose `event_types` includes this value. Payload: `capabilities-changed-webhook.json`. The payload does not include the full capability document; receivers SHOULD re-run `get_adcp_capabilities`, compare `adcp.capability_changes.capabilities_version` or `last_modified` when present, and update their cache from that fresh response. **notification_id**: stable per material capability revision; re-emissions of the same revision reuse the id, and a later material revision receives a new id.",
    "reporting.delivery_ready": "Experimental account-anchored readiness doorbell, managed-delivery tier only (it names a materialization at a destination; Core configurations never fire it). Fires after one immutable reporting materialization is observable through the intended consumer path. Payload: `reporting-delivery-ready-webhook.json`; it carries identities and readiness metadata, never report rows or credentials. Receivers repair missed, duplicate, or out-of-order fires through `get_reporting_status`. **notification_id**: stable per reporting_materialization_id reaching its ready state across re-emissions; a new retry/materialization receives a new id.",
    "reporting.status_changed": "Experimental account-anchored invalidation, valid in every reporting tier including Core. Fires when an obligation or configuration health state transitions in either direction — waiting to delayed, delayed to action_required, and recovery back to healthy or complete — including purely clock-driven transitions that no positive doorbell would ever announce. Payload: `reporting-status-changed-webhook.json`; it carries identifiers, the new health, and stable issue ids, never report rows. Push is optional in every tier: polling `get_reporting_status` remains the authoritative recovery path, and receivers repair every fire through it. **notification_id**: stable per (reporting_obligation_id or delivery_config_id, health transition); re-emissions reuse the id, and a later distinct transition receives a new id.",
    "principal.changed": "Caller-anchored invalidation. Sent when the seller changes the authenticated principal's standing configuration through a seller-driven transition that does not advance configuration_version: a reporting destination moving between validating, ready, action_required, and rejected, a setup action nearing or passing expires_at, a proof invalidation, or a change to the accepted declarations intersection. Not fired for the caller's own mutations — the sync response already reports those. Payload: `principal-changed-webhook.json`, an invalidation signal only; receivers repair by re-reading `get_principal`. **notification_id**: stable per logical principal-state transition; re-emissions reuse the id, and a later distinct transition receives a new id."
  }
}
