{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/account/sync-accounts-response.json",
  "title": "Sync Accounts Response",
  "description": "Response from account sync operation. Returns per-account results with status and billing, or operation-level errors on complete failure.",
  "type": "object",
  "allOf": [
    {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/version-envelope.json"
    },
    {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/protocol-envelope.json"
    }
  ],
  "oneOf": [
    {
      "title": "SyncAccountsSuccess",
      "description": "Sync operation processed accounts (individual accounts may be pending or have action=failed)",
      "type": "object",
      "properties": {
        "dry_run": {
          "type": "boolean",
          "description": "Whether this was a dry run (no actual changes made)"
        },
        "accounts": {
          "type": "array",
          "description": "Results for each account processed",
          "items": {
            "type": "object",
            "properties": {
              "account_id": {
                "type": "string",
                "description": "Seller-assigned account identifier. Use this in subsequent create_media_buy and other account-scoped operations when the seller's account model uses account_id references. For buyer-declared accounts, this may be echoed as the seller's internal handle, but the seller MUST continue accepting the natural-key AccountRef for subsequent calls.",
                "x-entity": "account"
              },
              "brand": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/brand-ref.json",
                "description": "Current canonical brand reference for the account."
              },
              "operator": {
                "type": "string",
                "description": "Current canonical operator domain. When an identity change is pending or rejected, this remains the current value rather than echoing the requested value."
              },
              "operator_unit": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/operator-unit.json",
                "description": "Current canonical operator-owned business unit, agency seat, or platform account. The stable id participates in the natural key; name is mutable display metadata. This is distinct from the seller/storefront account_id. When an identity change is pending or rejected, this remains the current value rather than echoing the requested value."
              },
              "revision": {
                "type": "integer",
                "minimum": 1,
                "description": "Current account revision after this operation. Incremented by each persisted settings change, identity-change request, or identity-change disposition; not incremented by dry runs, validation failures, or exact idempotency replays. Pass this value in the next settings-update entry to prevent lost updates."
              },
              "identity_change": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/account-identity-change.json",
                "description": "Pending or rejected desired operator identity. The top-level operator and operator_unit remain canonical until an approved change is applied."
              },
              "identity_change_preview": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/account-identity-change-preview.json",
                "description": "Dry-run-only preview of whether the requested identity would apply, require approval, or be blocked, plus evaluated resource impacts. This value is not persisted; canonical fields and revision remain current."
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$",
                "description": "Immutable account currency, echoed when the advertiser object is currency-bound."
              },
              "timezone": {
                "type": "string",
                "minLength": 1,
                "description": "Immutable operational timezone for this account. AdCP 3.2 sellers echo it on created, updated, and unchanged results. For buyer-selected account_fixed provisioning it participates in the natural key."
              },
              "name": {
                "type": "string",
                "description": "Human-readable account name assigned by the seller"
              },
              "action": {
                "type": "string",
                "enum": [
                  "created",
                  "updated",
                  "unchanged",
                  "failed"
                ],
                "description": "Action taken for this account. created: new account provisioned. updated: existing account modified. unchanged: no changes needed. failed: could not process (see errors)."
              },
              "status": {
                "type": "string",
                "enum": [
                  "active",
                  "pending_approval",
                  "rejected",
                  "payment_required",
                  "suspended",
                  "closed"
                ],
                "description": "Account status. active: ready for use. pending_approval: seller reviewing (credit, legal). rejected: seller declined the account request. payment_required: credit limit reached or funds depleted. suspended: was active, now paused. closed: was active, now terminated."
              },
              "billing": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/enums/billing-party.json",
                "description": "Who is invoiced on this account. Matches the requested billing model."
              },
              "billing_entity": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/business-entity.json",
                "description": "Current canonical business entity for the party responsible for payment. Sellers MAY add verified fields, but MUST NOT return data from a different entity. During an operator-domain handoff this remains the current entity until approval applies atomically; destination_billing_entity is staged and write-only. Bank details are omitted (write-only)."
              },
              "destination_billing_entity": {
                "description": "Request-only staging field. It MUST NOT appear in sync_accounts responses.",
                "not": {}
              },
              "account_scope": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/enums/account-scope.json"
              },
              "setup": {
                "type": "object",
                "description": "Setup information for pending accounts. Provides the agent (or human) with next steps to complete account activation.",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL where the human can complete the required action (credit application, legal agreement, add funds)"
                  },
                  "message": {
                    "type": "string",
                    "description": "Human-readable description of what's needed"
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When this setup link expires"
                  }
                },
                "required": [
                  "message"
                ],
                "additionalProperties": true
              },
              "rate_card": {
                "type": "string",
                "description": "Rate card applied to this account"
              },
              "payment_terms": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/enums/payment-terms.json",
                "description": "Payment terms agreed for this account. When the account is active, these are the binding terms for all invoices on this account."
              },
              "credit_limit": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number",
                    "minimum": 0
                  },
                  "currency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  }
                },
                "required": [
                  "amount",
                  "currency"
                ]
              },
              "errors": {
                "type": "array",
                "description": "Per-account errors (only present when action is 'failed')",
                "items": {
                  "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/error.json"
                }
              },
              "warnings": {
                "type": "array",
                "description": "Non-fatal warnings about this account",
                "items": {
                  "type": "string"
                }
              },
              "sandbox": {
                "type": "boolean",
                "description": "Whether this is a sandbox account, echoed from the request. Only present for buyer-declared accounts."
              },
              "notification_configs": {
                "type": "array",
                "description": "Applied notification subscribers for this account after declarative replacement and activation-proof checks. Present on `created`, `updated`, and `unchanged` results when the buyer included `notification_configs` in the request or any persisted entries exist on the account. Entries are keyed by account-scoped `subscriber_id`; re-sending an existing `subscriber_id` replaces that subscriber's config rather than creating a duplicate. Only configs that the seller has persisted are echoed. `authentication.credentials` is omitted on every entry (write-only).",
                "items": {
                  "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/notification-config.json"
                },
                "maxItems": 16
              },
              "authorization": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/account-authorization.json",
                "description": "Optional. The caller's scope grant against this account after the sync operation. Vendor agents of any type (media-buy, signals, governance, creative, brand) that support scope introspection SHOULD populate this so callers can preempt RBAC errors rather than discovering scope by trial and error. Media-buy sales agents claiming the `attestation_verifier` standard scope MUST populate it. Present on `created`, `updated`, and `unchanged` results; omitted on `failed` results (where the account did not reach a usable state). Absence means the vendor agent does not advertise introspectable scope — callers MUST NOT infer access from absence."
              }
            },
            "required": [
              "brand",
              "operator",
              "action",
              "status"
            ],
            "dependencies": {
              "identity_change": [
                "revision"
              ],
              "identity_change_preview": [
                "revision"
              ]
            },
            "not": {
              "required": [
                "destination_billing_entity"
              ]
            },
            "additionalProperties": true
          }
        },
        "context": {
          "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/context.json"
        },
        "ext": {
          "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/ext.json"
        }
      },
      "required": [
        "accounts"
      ],
      "additionalProperties": true,
      "not": {
        "required": [
          "errors"
        ]
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "dry_run": {
                "const": true
              }
            },
            "required": [
              "dry_run"
            ]
          },
          "then": {
            "properties": {
              "accounts": {
                "items": {
                  "not": {
                    "required": [
                      "identity_change"
                    ]
                  }
                }
              }
            }
          },
          "else": {
            "properties": {
              "accounts": {
                "items": {
                  "not": {
                    "required": [
                      "identity_change_preview"
                    ]
                  }
                }
              }
            }
          }
        }
      ]
    },
    {
      "title": "SyncAccountsError",
      "description": "Operation failed completely, no accounts were processed",
      "type": "object",
      "properties": {
        "errors": {
          "type": "array",
          "description": "Operation-level errors (e.g., authentication failure, service unavailable)",
          "items": {
            "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/error.json"
          },
          "minItems": 1
        },
        "context": {
          "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/context.json"
        },
        "ext": {
          "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/ext.json"
        }
      },
      "required": [
        "errors"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "accounts"
            ]
          },
          {
            "required": [
              "dry_run"
            ]
          }
        ]
      }
    }
  ],
  "examples": [
    {
      "description": "Mixed results — one active, one pending approval",
      "data": {
        "status": "completed",
        "accounts": [
          {
            "account_id": "acc_spark_001",
            "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",
            "name": "Spark (via EMEA)",
            "action": "created",
            "status": "active",
            "billing": "operator",
            "account_scope": "operator_brand"
          },
          {
            "account_id": "acc_glow_pending",
            "brand": {
              "domain": "nova-brands.com",
              "brand_id": "glow"
            },
            "operator": "pinnacle-media.com",
            "name": "Glow",
            "action": "created",
            "status": "pending_approval",
            "billing": "operator",
            "account_scope": "operator_brand",
            "setup": {
              "url": "https://seller.example.com/advertiser-onboard",
              "message": "Complete advertiser registration and credit application",
              "expires_at": "2026-03-10T00:00:00Z"
            }
          }
        ]
      }
    },
    {
      "description": "Rejected account — no account_id assigned",
      "data": {
        "status": "completed",
        "accounts": [
          {
            "brand": {
              "domain": "acme-corp.com",
              "brand_id": "clearance"
            },
            "operator": "acme-corp.com",
            "action": "created",
            "status": "rejected",
            "warnings": [
              "Account request declined: advertiser category not accepted on this platform."
            ]
          }
        ]
      }
    },
    {
      "description": "Unsupported billing — seller rejects the request",
      "data": {
        "status": "completed",
        "accounts": [
          {
            "brand": {
              "domain": "acme-corp.com"
            },
            "operator": "acme-corp.com",
            "action": "failed",
            "status": "rejected",
            "errors": [
              {
                "code": "BILLING_NOT_SUPPORTED",
                "message": "Operator billing is not supported. This seller only accepts agent billing."
              }
            ]
          }
        ]
      }
    },
    {
      "description": "Advertiser billed directly with billing entity (bank details omitted in response)",
      "data": {
        "status": "completed",
        "accounts": [
          {
            "account_id": "acc_acme_direct_bill",
            "brand": {
              "domain": "acme-corp.com"
            },
            "operator": "pinnacle-media.com",
            "name": "Acme Corp (billed direct)",
            "action": "created",
            "status": "active",
            "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"
                }
              ]
            },
            "account_scope": "operator_brand",
            "payment_terms": "net_30"
          }
        ]
      }
    },
    {
      "description": "Unsupported payment terms — seller rejects the request",
      "data": {
        "status": "completed",
        "accounts": [
          {
            "brand": {
              "domain": "acme-corp.com"
            },
            "operator": "acme-corp.com",
            "action": "failed",
            "status": "rejected",
            "errors": [
              {
                "code": "PAYMENT_TERMS_NOT_SUPPORTED",
                "message": "Net-60 payment terms are not available. Omit payment_terms to accept this seller's default terms (net_30)."
              }
            ]
          }
        ]
      }
    }
  ],
  "properties": {}
}
