{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/account/sync-accounts-request.json",
  "title": "Sync Accounts Request",
  "description": "Sync advertiser account state with a seller. Two modes, distinguished by the key on each per-account entry:\n\n- **Provisioning mode** (`brand` + `operator` + `billing` at the entry root, no `account`): opens an account. The agent names the brand and the operator, the account's parties, and sets the billing model and the account attributes. The account attributes are `brand.countries`, optional operator-owned `operator_unit`, optional fixed `currency`, conditionally required buyer-selected `timezone`, and `sandbox`. The seller MUST return the seller-assigned account_id, which is the account's identity, once the account is resolved. A seller never issues an account_id it might later change, so a pending_approval row that may still resolve to a different account carries request_id (experimental, account.requests) instead. A retry with the same idempotency_key returns the original result instead of opening another account. A provisioning entry never changes an existing account. When the entry matches exactly one account in the seller's account_scope, the seller SHOULD return that account_id instead of opening another, and the result row echoes the account's own attributes. A match follows the request_account deduplication guidance (/docs/accounts/tasks/request_account#deduplication): brand and operator, with each supplied attribute as a filter and billing terms never filtering. The exact-or-reject rules for billing and payment_terms still apply.\n\n- **Settings-update mode** (`account` field carrying an [`AccountRef`](/schemas/core/account-ref.json)): targets an existing account, preferably by `account_id`. The seller updates settable state and account attributes, `brand.countries` and `billing` included, without provisioning side effects. On this task, attribute changes go only through settings-update mode; request_account (account.requests) changes attributes too. The seller validates a changed attribute as it does when the account opens and rejects the entry with the same error. Currency, timezone, and sandbox are set at opening: a seller MAY refuse a currency or timezone change with `UNSUPPORTED_FEATURE`, and sandbox never changes. A seller that reviews a countries change reports `pending_approval` on the entry's result row, and the account keeps its current countries until the seller approves. The account_id never changes.\n\nExactly one key shape is allowed per entry. A seller that opens buyer-declared accounts through sync_accounts accepts settings-update entries keyed by account_id and declines an attribute change it cannot make with `UNSUPPORTED_FEATURE`. A seller that does not provision through sync_accounts returns `UNSUPPORTED_PROVISIONING` for a provisioning entry, and an account-id-namespace seller that does not expose settings updates returns it for a settings-update entry. The deprecated `operator_identity` reconciliation is additionally gated by the deprecated `get_adcp_capabilities.account.identity_updates`.\n\nWhere the seller supports the experimental account.requests surface (#8543), request_account opens and changes accounts, list_accounts reads them and their requests, and, where the seller supports them (account.status_changed in caller_event_types, media_buy.reporting_subscriptions), sync_principal registers webhooks and reporting; buyers SHOULD use those there. This task stays stable and available in 3.3, and is the path with sellers that do not support account.requests; its formal deprecation follows account.requests leaving experimental status. An entry that carries only notification_configs and/or reporting_delivery_configs is a subscription write: it MUST name an account the caller already holds (otherwise ACCOUNT_NOT_FOUND), and the seller MUST NOT provision, run account review, or change account attributes for it; it does not advance the account revision.",
  "x-tool-summary": "Provision advertiser accounts or update settings for existing accounts through declarative synchronization.",
  "type": "object",
  "allOf": [
    {
      "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/version-envelope.json"
    }
  ],
  "x-mutates-state": true,
  "properties": {
    "idempotency_key": {
      "type": "string",
      "description": "Client-generated unique key for at-most-once execution. A provisioning entry can open an account, so this key is what prevents a retry from opening a second account and from firing onboarding webhooks, billing setup, and audit events twice. MUST be unique per (seller, request) pair. Use a fresh UUID v4 for each request.",
      "minLength": 16,
      "maxLength": 255,
      "pattern": "^[A-Za-z0-9_.:-]{16,255}$"
    },
    "accounts": {
      "type": "array",
      "description": "Per-account sync entries. Each entry uses one of two key shapes: the `account` field (AccountRef) for settings-update mode, or the flat `brand` + `operator` + `billing` trio for provisioning mode. A deprecated operator_identity settings update MUST carry the latest account revision.",
      "items": {
        "type": "object",
        "description": "An advertiser account entry — either opens an account (no account field) or updates an existing one (AccountRef key).",
        "properties": {
          "account": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/account-ref.json",
            "description": "Settings-update key. When present, this entry targets an existing account, preferably by `account_id`. A natural key resolves only when exactly one of the caller's accounts matches it, otherwise the entry fails with ACCOUNT_AMBIGUOUS. Mutually exclusive with the flat `brand` + `operator` + `billing` provisioning trio. When `account` is present, the seller MUST NOT create a new account — entries that would otherwise trigger provisioning are rejected with `UNSUPPORTED_PROVISIONING`."
          },
          "revision": {
            "type": "integer",
            "minimum": 1,
            "description": "Expected current account revision for optimistic concurrency in settings-update mode. Required whenever operator_identity is present; optional for existing non-identity settings updates. The seller MUST compare it atomically with the write, reject a mismatch with CONFLICT, and leave the account unchanged. Obtain it from list_accounts or the most recent sync_accounts result. Reads, dry runs, validation failures, and exact idempotency replays do not increment revision; every persisted settings or identity-change state transition does. MUST be absent in provisioning mode."
          },
          "operator_identity": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/operator-identity.json",
            "deprecated": true,
            "x-deprecated-in": "3.3.0",
            "description": "Deprecated in 3.3 and planned for removal in 4.0, with the account.identity_updates capability that gates it: an account's identity is its account_id, so operator_unit is an account attribute set directly in settings-update mode. Complete desired operator identity for settings-update mode. Omit this field to leave operator identity unchanged. When present, omission of operator_unit within the object removes the existing unit. Changing only operator_unit.name updates display metadata; changing operator_unit.id or adding/removing a unit rekeys the same account within the current operator. Changing operator requests an inter-entity handoff and MUST enter pending_approval until the seller verifies the current account authority, verified brand authorization, destination-operator acceptance, and any operator-scoped billing and grant transition. The seller MUST preserve account_id and account-scoped historical resources, MUST reject collisions without merging, and MUST apply no identity change if continuity cannot be preserved. MUST be accompanied by revision and MUST be absent in provisioning mode."
          },
          "destination_billing_entity": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/business-entity.json",
            "deprecated": true,
            "x-deprecated-in": "3.3.0",
            "description": "Deprecated in 3.3 with operator_identity. Complete staged billing identity for the requested destination operator during an operator-domain handoff on an account whose billing party is operator. This value is write-only while approval is pending and MUST NOT replace or be echoed as the account's canonical billing_entity until the handoff applies atomically. Required by the protocol when an operator-billed account changes operator; otherwise MUST be absent. Requires operator_identity and revision and MUST be absent in provisioning mode."
          },
          "brand": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/brand-ref.json",
            "description": "Brand reference identifying the advertiser. Required for **provisioning mode**. `domain` and optional `brand_id` identify the brand; `countries` sets the account attribute. In settings-update mode, `brand` updates `countries`; its `domain` and `brand_id` MUST equal the account's, and the seller rejects a different brand with INVALID_REQUEST. A seller MAY review a countries change and report `pending_approval` on the entry's result row. Per-call BrandRef fields such as `industries`, `data_subject_contestation`, and `brand_kit_override` MUST NOT affect lookup, idempotency, or account creation. New 3.2 producers SHOULD send only the BrandKey fields; the broader BrandRef remains accepted on this existing 3.x task for compatibility."
          },
          "operator": {
            "type": "string",
            "description": "Domain of the entity operating on the brand's behalf (e.g., 'pinnacle-media.com'). When the brand operates directly, this is the brand's domain. Verified against the brand's authorized_operators in brand.json. Required for **provisioning mode**; MUST be absent in settings-update mode.",
            "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$"
          },
          "operator_unit": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/operator-unit.json",
            "description": "Optional operator-owned business unit, agency seat, or platform account. An account attribute, set in provisioning mode and updatable in settings-update mode; name is mapping/display metadata."
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$",
            "description": "Optional ISO 4217 transaction currency for a currency-bound advertiser object. Consult `account.supported_account_currency_modes` before provisioning. An account attribute: all media buys on the account use it. Omit for per-media-buy currency selection. Set when the account opens: a seller MAY refuse a change with UNSUPPORTED_FEATURE."
          },
          "timezone": {
            "type": "string",
            "minLength": 1,
            "description": "Operational timezone selected for an account_fixed advertiser object. Required in provisioning mode when get_adcp_capabilities.account.timezone declares account_selection: buyer_selected, and the value MUST be one of supported_timezones. Omit for seller_fixed or seller_assigned modes. An account attribute set when the account opens: a seller MAY refuse a change with UNSUPPORTED_FEATURE."
          },
          "billing": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/enums/billing-party.json",
            "description": "Who the seller invoices for this buyer–storefront account relationship. Required for **provisioning mode**. An account attribute: in settings-update mode it changes the invoiced party on the same account, and a seller that cannot make that change rejects the entry with UNSUPPORTED_FEATURE. This field does not select a payment rail, clearing intermediary, or per-media-buy settlement route."
          },
          "billing_entity": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/business-entity.json",
            "description": "Business entity details for the party responsible for payment. The agent provides this so the seller has the legal name, tax IDs, address, and bank details needed for formal B2B invoicing. Permitted in both modes — sellers MAY accept refinements in settings-update mode (e.g., updated bank details)."
          },
          "payment_terms": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/enums/payment-terms.json",
            "description": "Payment terms for this account. The seller must either accept these terms or reject the account — terms are never silently remapped. When omitted, the seller applies its default terms. Permitted in both modes."
          },
          "sandbox": {
            "type": "boolean",
            "description": "When true, open this as a sandbox account with no real platform calls or billing. An account attribute set when the account opens; it never changes, and a seller refuses a different value in settings-update mode with UNSUPPORTED_FEATURE. Applicable to buyer-declared accounts (require_operator_auth: false). For account-id namespaces, sandbox accounts are pre-existing test accounts discovered via list_accounts or supplied out-of-band."
          },
          "preferred_reporting_protocol": {
            "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/enums/cloud-storage-protocol.json",
            "description": "Buyer's preferred cloud storage protocol for offline reporting delivery. The seller provisions the account's reporting_bucket using this protocol if supported. When omitted, the seller chooses from its supported offline_delivery_protocols. Only meaningful when the seller's reporting_delivery_methods includes 'offline'."
          },
          "reporting_delivery_configs": {
            "type": "array",
            "x-status": "experimental",
            "description": "Caller-owned desired state for durable reporting delivery on this account. Declarative replacement is scoped to (authenticated caller, resolved account): omission leaves that caller's set unchanged; [] deactivates that caller's set and starts grant revocation; another caller's entries MUST NOT be read, replaced, or deleted. Entries are keyed by immutable (delivery_config_id, delivery_config_version); duplicate tuples MUST reject the entire account entry, and reusing a tuple with changed content MUST be rejected. Each generation binds the exact report_definition_id advertised by its offering. destination.mode provision asks the seller to verify caller disclosure authority and destination/recipient control from non-secret provider coordinates; destination.mode existing reuses a caller-scoped immutable destination-generation reference, including one registered through sync_agent_configuration. The account configuration independently authorizes disclosure for this feed and scope, so possession of a reusable reference is never account authority. Unknown, unauthorized, and cross-caller refs MUST be indistinguishable. Credentials never transit AdCP, including nested extension fields. Permitted in both provisioning and settings-update modes. Sellers accepting this field MUST advertise media_buy.reporting_delivery in experimental_features and echo resolved secret-free state on sync_accounts and list_accounts. delivery_config_id shares a namespace with the caller's sync_principal reporting subscription_id values: an entry whose delivery_config_id equals one of the caller's subscription_id values MUST be rejected. An active entry takes precedence over every reporting subscription of the same caller for this account and its feed_purpose; it never affects another caller's subscriptions.",
            "items": {
              "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/reporting-delivery-config.json"
            },
            "maxItems": 16,
            "x-adcp-validation": {
              "unique_config_generation": "Reject the account entry when two items share delivery_config_id and delivery_config_version.",
              "immutable_generation": "A previously observed tuple must retain identical feed/profile/scope/finality/schedule/method/destination content. Only active and revocation_effective_at are mutable lifecycle intent.",
              "authorization": "Verify authenticated-caller authority for the account, requested reporting scope, recipient, and destination before applying."
            }
          },
          "notification_configs": {
            "type": "array",
            "description": "Account-level webhook subscriptions for notifications whose lifecycle outlives any single media buy (`creative.status_changed`, optional `creative.assignment_changed`, `indicators.changed`, `creative.purged`, `account.status_changed`, wholesale feed change payloads, and future account-anchored resource events after those event types are added to `notification-config.json`). Indicator and assignment registrations are prospective: activation does not replay current conditions, so buyers establish a complete baseline through `get_media_buys` by enumerating known IDs or requesting every status and exhausting pagination, without an indicator filter. Durable account lifecycle transitions such as later `payment_required`, `suspended`, `closed`, or recovery to `active` use `account.status_changed` on this surface; the one-shot `sync_accounts.push_notification_config` channel remains scoped to the async result of the original provisioning task. Declarative replace semantics: when this field is present, the buyer sends the full desired array and the seller replaces the account's current set with that array, keyed by account-scoped `subscriber_id`. Omit this field to leave existing subscribers unchanged; send `[]` to remove all subscribers. Re-sending an existing `subscriber_id` for the account replaces that subscriber's config rather than creating a duplicate; persisted entries whose `subscriber_id` does not appear in the sent array are removed, so the seller MUST NOT merge the new array with persisted state. Paused entries (`active: false`) use the same replacement semantics; a buyer that wants to preserve a paused subscriber MUST re-include it with `active: false`. Duplicate `subscriber_id` values within one submitted array are rejected. Permitted in both provisioning and settings-update modes. Each entry registers a URL, the event types the subscriber wants, and optional legacy auth — see [`notification-config.json`](/schemas/core/notification-config.json). The seller MUST echo applied state on the response and on `list_accounts` reads, with `authentication.credentials` omitted (write-only). Sellers MUST reject entries whose `event_types` include any type whose contract anchors at a media buy or below (today: `scheduled`, `final`, `delayed`, `adjusted`, `window_update`, `impairment`) or at the agent (today: `capabilities.changed`) as per-account validation failures with `INVALID_REQUEST` or `VALIDATION_ERROR` and `error.field` pointing at the invalid `event_types` entry — those events do not belong on this surface. Wholesale feed webhook registrations carry the actual change payload in `/schemas/core/wholesale-feed-webhook.json`; canonical product subscribers repair through `list_products(if_feed_version)`, legacy product subscribers through `get_products(if_wholesale_feed_version)`, and signal subscribers through `get_signals(if_wholesale_feed_version)`. Account status change registrations carry the invalidation payload in `/schemas/core/account-status-changed-webhook.json`; receivers use `list_accounts` to repair or reconcile. This is distinct from sync_catalogs, which manages buyer-provided campaign input feeds on a seller account.\n\nActivation proof: before activating a new or changed active subscriber, the seller MUST validate the URL, complete the account-level webhook proof-of-control challenge, and only then persist or expose the subscriber as `active: true`. For `account.status_changed`, sellers MUST assign `account_id` before completing proof so subsequent status transitions can identify the account and be repaired through `list_accounts`, even when external approval remains pending. A valid existing proof for the same `(account_id, subscriber_id, normalized url, authentication mode/credential binding, normalized event_types)` tuple MAY be reused; changing any element of that tuple requires fresh proof. The challenge POST itself MUST be signed with the seller's RFC 9421 webhook profile key and MUST include seller_agent_url, delivery_auth, and event_types so the receiver can verify the pending registration before echoing the challenge. New signers use `adcp_use: \"request-signing\"`; deprecated `webhook-signing` keys remain accepted during the compatibility window. Entries sent with `active: false` may skip only the outbound proof challenge while inactive; sellers MUST still enforce URL parsing, HTTPS, hostname normalization, and reserved-range rejection at write time, and those entries MUST NOT receive fires until reactivated. If proof fails or times out, the seller rejects the account entry with `action: \"failed\"`, leaves the prior notification_configs[] set unchanged, and reports `VALIDATION_ERROR` (or `INVALID_REQUEST` for malformed URLs) at the failing `notification_configs[j].url` field.\n\n**Cap rationale:** `maxItems: 16` is a practical fan-out cap (governance + buyer ingestion + audit bus + dx team + a few partner hooks). The cap exists to prevent unbounded subscriber arrays in storage and to bound the seller's per-event fan-out work. Sellers that hit the cap with legitimate subscribers should surface this on the protocol roadmap rather than work around it.",
            "items": {
              "allOf": [
                {
                  "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/notification-config.json"
                },
                {
                  "if": {
                    "required": [
                      "authentication"
                    ]
                  },
                  "then": {
                    "properties": {
                      "authentication": {
                        "required": [
                          "credentials"
                        ]
                      }
                    }
                  }
                }
              ]
            },
            "maxItems": 16
          }
        },
        "oneOf": [
          {
            "title": "ProvisioningMode",
            "description": "Provisioning-mode entry — brand, operator, and billing are required; account, revision, and operator_identity are forbidden.",
            "required": [
              "brand",
              "operator",
              "billing"
            ],
            "allOf": [
              {
                "not": {
                  "required": [
                    "account"
                  ]
                }
              },
              {
                "not": {
                  "required": [
                    "revision"
                  ]
                }
              },
              {
                "not": {
                  "required": [
                    "operator_identity"
                  ]
                }
              },
              {
                "not": {
                  "required": [
                    "destination_billing_entity"
                  ]
                }
              }
            ]
          },
          {
            "title": "SettingsUpdateMode",
            "description": "Settings-update entry — `account` (AccountRef) is required and `operator` is forbidden. Account attributes (`brand.countries`, `operator_unit`, `currency`, `timezone`, `sandbox`, `billing`) are permitted; `sandbox` never changes.",
            "required": [
              "account"
            ],
            "not": {
              "required": [
                "operator"
              ]
            }
          }
        ],
        "dependencies": {
          "operator_identity": [
            "revision"
          ],
          "destination_billing_entity": [
            "operator_identity",
            "revision"
          ]
        },
        "additionalProperties": true
      },
      "maxItems": 1000
    },
    "delete_missing": {
      "type": "boolean",
      "default": false,
      "description": "When true, the seller deactivates accounts this agent previously synced that this request does not include. An account counts as included only when an entry names it by `account` or the seller returns its account_id for an entry. A provisioning entry can open an account, so a buyer that keeps an account sends it as an `{ \"account\": { \"account_id\": ... } }` entry. Scoped to the authenticated agent — does not affect accounts managed by other agents. Use with caution."
    },
    "dry_run": {
      "type": "boolean",
      "default": false,
      "description": "When true, preview what would change without applying. Returns what would be created/updated/deactivated."
    },
    "push_notification_config": {
      "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/push-notification-config.json",
      "description": "Webhook for async notifications when account status changes (e.g., pending_approval transitions to active)."
    },
    "context": {
      "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/context.json"
    },
    "ext": {
      "$ref": "https://adcontextprotocol.org/schemas/3.3.0-beta.1/core/ext.json"
    }
  },
  "required": [
    "idempotency_key",
    "accounts"
  ],
  "additionalProperties": true,
  "examples": [
    {
      "description": "Agency syncing multiple advertisers with different billing",
      "data": {
        "idempotency_key": "a7f9c2e4-1234-4567-89ab-cdef01234567",
        "accounts": [
          {
            "brand": {
              "domain": "nova-brands.com",
              "brand_id": "spark",
              "countries": [
                "DE",
                "NL"
              ]
            },
            "operator": "pinnacle-media.com",
            "operator_unit": {
              "id": "seat_emea_01",
              "name": "EMEA"
            },
            "currency": "EUR",
            "billing": "operator"
          },
          {
            "brand": {
              "domain": "nova-brands.com",
              "brand_id": "glow"
            },
            "operator": "pinnacle-media.com",
            "billing": "agent"
          }
        ]
      }
    },
    {
      "description": "Brand buying direct with payment terms",
      "data": {
        "idempotency_key": "b8e0d3f5-2345-4678-9abc-def012345678",
        "accounts": [
          {
            "brand": {
              "domain": "acme-corp.com"
            },
            "operator": "acme-corp.com",
            "billing": "operator",
            "payment_terms": "net_30"
          }
        ]
      }
    },
    {
      "description": "Agent consolidating billing with net-60 terms",
      "data": {
        "idempotency_key": "c9f1e4a6-3456-4789-abcd-ef0123456789",
        "accounts": [
          {
            "brand": {
              "domain": "nova-brands.com",
              "brand_id": "spark"
            },
            "operator": "pinnacle-media.com",
            "billing": "agent",
            "payment_terms": "net_60"
          },
          {
            "brand": {
              "domain": "nova-brands.com",
              "brand_id": "glow"
            },
            "operator": "pinnacle-media.com",
            "billing": "agent",
            "payment_terms": "net_60"
          }
        ]
      }
    },
    {
      "description": "Advertiser billed directly with structured billing entity (DACH B2B)",
      "data": {
        "idempotency_key": "d0a2f5b7-4567-489a-bcde-f01234567890",
        "accounts": [
          {
            "brand": {
              "domain": "acme-corp.com"
            },
            "operator": "pinnacle-media.com",
            "billing": "advertiser",
            "billing_entity": {
              "legal_name": "Acme Corporation GmbH",
              "vat_id": "DE987654321",
              "registration_number": "HRB 67890",
              "address": {
                "street": "Hauptstrasse 42",
                "city": "Munich",
                "postal_code": "80331",
                "country": "DE"
              },
              "contacts": [
                {
                  "role": "billing",
                  "name": "AP Department",
                  "email": "billing@acme-corp.com"
                }
              ],
              "bank": {
                "account_holder": "Acme Corporation GmbH",
                "iban": "DE75512108001245126199",
                "bic": "SOLADEST600"
              }
            },
            "payment_terms": "net_30"
          }
        ]
      }
    },
    {
      "description": "Provisioning mode — register a creative-lifecycle webhook subscription alongside account provisioning",
      "data": {
        "idempotency_key": "e1b3a6c8-5678-49ab-cdef-1234567890ab",
        "accounts": [
          {
            "brand": {
              "domain": "acme-corp.com"
            },
            "operator": "acme-corp.com",
            "billing": "operator",
            "notification_configs": [
              {
                "subscriber_id": "buyer-primary",
                "url": "https://buyer.example/webhooks/adcp/creative",
                "event_types": [
                  "creative.status_changed",
                  "creative.purged"
                ],
                "active": true
              }
            ]
          }
        ]
      }
    },
    {
      "description": "Settings-update mode — register webhook subscribers on an existing account-id namespace account",
      "data": {
        "idempotency_key": "f2c4b7d9-6789-49bc-defa-2345678901bc",
        "accounts": [
          {
            "account": {
              "account_id": "acc_acme_pinnacle"
            },
            "notification_configs": [
              {
                "subscriber_id": "buyer-primary",
                "url": "https://buyer.example/webhooks/adcp/creative",
                "event_types": [
                  "creative.status_changed",
                  "creative.purged"
                ],
                "active": true
              },
              {
                "subscriber_id": "audit-bus",
                "url": "https://audit.buyer.example/adcp/ingest",
                "event_types": [
                  "creative.status_changed",
                  "creative.purged"
                ],
                "active": true
              }
            ]
          }
        ]
      }
    },
    {
      "description": "Settings-update mode — register a wholesale feed mirror webhook subscriber for wholesale product and signal changes",
      "data": {
        "idempotency_key": "a8af8cf1-89bd-41f3-b27d-7ee7e9f8d2e4",
        "accounts": [
          {
            "account": {
              "account_id": "acc_acme_pinnacle"
            },
            "notification_configs": [
              {
                "subscriber_id": "wholesale-feed-sync",
                "url": "https://buyer.example/webhooks/adcp/wholesale-feed",
                "event_types": [
                  "product.created",
                  "product.updated",
                  "product.priced",
                  "product.removed",
                  "signal.created",
                  "signal.updated",
                  "signal.priced",
                  "signal.removed",
                  "wholesale_feed.bulk_change"
                ],
                "active": true
              }
            ]
          }
        ]
      }
    }
  ]
}
