{
  "openapi": "3.1.0",
  "info": {
    "title": "WireBloom Banking Platform API",
    "version": "1.0.0-draft.14",
    "summary": "The public integrator contract: every operation an API key can call on a customer account, the webhook events and their payloads.",
    "description": "Contract for the WireBloom Banking Platform API v1 (P2-T03). Human guide: `docs/api/API.md`.\n\n**Conventions (summary)**\n\n- JSON in camelCase; unknown response fields must be ignored by clients (additive changes are non-breaking).\n- Ids are UUIDs; timestamps RFC 3339 UTC; dates ISO 8601; money `{amountMinor: string(int64), currency: ISO 4217}`.\n- Tenancy: `X-Tenant-Id` on every tenant-scoped operation (`x-tenant: customer | operator | any`).\n- Errors: RFC 9457 `application/problem+json` (`Problem`).\n- Lists: cursor pagination `{data, page:{nextCursor, prevCursor, limit, total?}}` with `cursor`, `limit` (≤100), `sort`, `filter[...]`.\n- Money operations require `Idempotency-Key`; mutable resources use `ETag`/`If-Match`.\n",
    "contact": {
      "name": "WireBloom Platform Engineering",
      "url": "https://banking.wirebloom.com"
    },
    "license": {
      "name": "Proprietary",
      "identifier": "LicenseRef-WireBloom-Proprietary"
    }
  },
  "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base",
  "servers": [
    {
      "url": "https://api.banking.wirebloom.com/v1",
      "description": "Production"
    },
    {
      "url": "https://api.staging.banking.wirebloom.com/v1",
      "description": "Staging (provider sandboxes; `wb_test_` keys)"
    },
    {
      "url": "http://localhost:3001/v1",
      "description": "Local development"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "tenants",
      "description": "Operators, customers, people (memberships), invitations, teams and customer settings (currencies, addresses, alerts, approved domains, approval policies, primary owner, closure)."
    },
    {
      "name": "onboarding",
      "description": "Customer KYB case: wizard data, persons (directors, UBOs), documents, submission, KYC provider SDK tokens, operator review queue and decisions (D-22)."
    },
    {
      "name": "accounts",
      "description": "Balances (ledger accounts per currency and sub-balances), account details per rail, journal with running balance, statements, currencies."
    },
    {
      "name": "recipients",
      "description": "Recipients (beneficiaries): requirements per currency/country, CRUD, Confirmation/Verification of Payee, approval (customer tier or operator queue, D-14)."
    },
    {
      "name": "payments",
      "description": "Payments, internal transfers, add money, exchanges and quotes, forward contracts and held rates, scheduled payments, direct debits (mandates, collections), bulk payments, approvals and funds requests."
    },
    {
      "name": "activity",
      "description": "Unified transactions (ledger view) with filters, search and exports; transaction detail with updates, annotations, attachments and confirmations; documents and asynchronous jobs."
    },
    {
      "name": "providers",
      "description": "Operator banking-partner configuration: provider connections (write-only credentials), routing rules, KYC connections, inbound provider webhooks and the provider event log."
    },
    {
      "name": "public-api",
      "description": "Integrator access: API keys with scopes and integrator webhooks (HMAC-signed callbacks). All other resources are shared with the web/mobile API and documented per scope."
    },
    {
      "name": "developer",
      "description": "Self-serve developer sandboxes (D-42, FR-PLAT-07): registration (open mode) with email verification and abuse limits, the developer workspace, and the operator / platform controls (invite or open per operator, capped per environment)."
    },
    {
      "name": "simulations",
      "description": "Sandbox simulations (SC-38, P-89): every asynchronous outcome on demand — incoming payments and debits, payment status, returns and recalls, inbound recalls, exchange settlement, FX rate moves, direct-debit outcomes, card events, KYC outcomes, integrator events, statements, scheduled runs and provider outages. Backed by the sandbox bank, and by the Banking Circle and Integrated Finance sandboxes where they offer a simulation."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Customer & identity",
      "tags": [
        "tenants",
        "onboarding"
      ]
    },
    {
      "name": "Money",
      "tags": [
        "accounts",
        "recipients",
        "payments",
        "activity"
      ]
    },
    {
      "name": "Operator",
      "tags": [
        "providers"
      ]
    },
    {
      "name": "Integrators",
      "tags": [
        "public-api",
        "developer",
        "simulations"
      ]
    }
  ],
  "paths": {
    "/add-money": {
      "post": {
        "operationId": "addMoney",
        "tags": [
          "payments"
        ],
        "summary": "Add money (deposit details or conversion order)",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddMoneyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddMoneyResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/approvals": {
      "get": {
        "operationId": "listApprovals",
        "tags": [
          "payments"
        ],
        "summary": "Approvals inbox",
        "description": "Customer members see their customer's approvals. **Operator staff** (`x-tenant: any`): with `X-Tenant-Id` set to a customer they read that customer; with their operator id they read every customer of the operator (RLS operator scope) (approvals oversight); staff never decide customer approvals, so `mine` returns nothing for them and `canDecide` is false. `filter[subjectId]` lists the approvals of one payment, recipient or bulk upload.\n\n**API key scope:** `payments:read`.\n\n**Conditional GET (P12-T07):** the response carries a weak `ETag` of its content; send it back as `If-None-Match` when polling and the API answers `304` without a body while nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "description": "Comma-separated ApprovalStatus (default `pending`)."
                },
                "subjectType": {
                  "type": "string"
                },
                "subjectId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "mine": {
                  "type": "boolean",
                  "description": "Only approvals the caller can decide."
                },
                "requestedByMe": {
                  "type": "boolean",
                  "description": "Only requests the caller made."
                },
                "customerId": {
                  "type": "string",
                  "description": "Comma-separated customer ids (operator tenant only)."
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "withTotal",
            "in": "query",
            "required": false,
            "description": "Include `page.total` (may be slower). P12-T07: `limit=1&withTotal=true` is the count-only form for badges.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApprovalPage"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/approvals/{approvalId}": {
      "get": {
        "operationId": "getApproval",
        "tags": [
          "payments"
        ],
        "summary": "Get approval",
        "description": "Read access as `GET /approvals` (operator staff: any customer of the operator).\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "approvalId",
            "in": "path",
            "required": true,
            "description": "Identifier (approvalId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Approval"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/attachments": {
      "get": {
        "operationId": "listAttachments",
        "tags": [
          "activity"
        ],
        "summary": "List attachments across transactions",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "transactionId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "createdFrom": {
                  "type": "string",
                  "format": "date-time"
                },
                "createdTo": {
                  "type": "string",
                  "format": "date-time"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachmentPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/attachments/{attachmentId}": {
      "get": {
        "operationId": "getAttachment",
        "tags": [
          "activity"
        ],
        "summary": "Get attachment",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "attachmentId",
            "in": "path",
            "required": true,
            "description": "Identifier (attachmentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Attachment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/attachments/{attachmentId}/download": {
      "get": {
        "operationId": "downloadAttachment",
        "tags": [
          "activity"
        ],
        "summary": "Pre-signed download link",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "attachmentId",
            "in": "path",
            "required": true,
            "description": "Identifier (attachmentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DownloadLink"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/balances": {
      "get": {
        "operationId": "listBalances",
        "tags": [
          "accounts"
        ],
        "summary": "List balances",
        "description": "Balances tab (All / Favourites / per currency). Amounts are real-time from `ledger.account_balances`. **Operator staff** (`x-tenant: any`): with `X-Tenant-Id` set to a customer they read that customer; with their operator id they read every customer of the operator (RLS operator scope), optionally narrowed with `filter[customerId]`.\n\n**API key scope:** `balances:read`.\n\n**Metadata filter:** `filter[metadata.<key>]=<value>` (exact match; at most 5; AND).\n\n**Batch look-up (P12-T07):** `filter[id]=<id>,<id>,…` (at most 100) returns those rows only, e.g. to resolve names shown next to ids; combine with `limit` ≥ the number of ids.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "currency",
                "-available",
                "name",
                "-createdAt"
              ],
              "default": "currency"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date). P10-T03: `filter[metadata.<key>]=<value>` matches a metadata attribute exactly (key `[A-Za-z0-9_-]{1,40}`; at most 5 per request, AND-combined, one value each).",
            "schema": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string",
                  "description": "Comma-separated ISO 4217 codes."
                },
                "favourite": {
                  "type": "boolean"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "customer_balance",
                    "customer_sub_balance"
                  ]
                },
                "status": {
                  "type": "string"
                },
                "customerId": {
                  "type": "string",
                  "description": "Comma-separated customer ids (operator tenant only; ignored for a customer tenant)."
                },
                "id": {
                  "type": "string",
                  "description": "P12-T07: comma-separated ids (at most 100): the batch id → name look-up of the pickers (`400 too_many_filter_values` above the cap). Unknown or foreign ids are simply absent."
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalancePage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/balances/{balanceId}": {
      "get": {
        "operationId": "getBalance",
        "tags": [
          "accounts"
        ],
        "summary": "Get balance",
        "description": "**API key scope:** `balances:read`.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/balances/{balanceId}/details": {
      "get": {
        "operationId": "getBalanceAccountDetails",
        "tags": [
          "accounts"
        ],
        "summary": "Account details (local and SWIFT)",
        "description": "`status: pending` until the partner has provisioned the account.\n\n**API key scope:** `balances:read`.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "rail",
            "in": "query",
            "required": false,
            "description": "Limit to one rail.",
            "schema": {
              "type": "string",
              "enum": [
                "local",
                "swift"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AccountDetails"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/balances/{balanceId}/holds": {
      "get": {
        "operationId": "listBalanceHolds",
        "tags": [
          "accounts"
        ],
        "summary": "Pending holds on a balance",
        "description": "**API key scope:** `balances:read`.\n\n**Review holds (P10R-01):** a hold placed while a payment is reviewed is listed with subject type `payment_review`, its own id as subject id and a neutral description; the amount counts against the available balance like any other hold.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "description": "Comma-separated HoldStatus (default `active`)."
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HoldPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/balances/{balanceId}/journal": {
      "get": {
        "operationId": "listBalanceJournal",
        "tags": [
          "accounts"
        ],
        "summary": "Journal lines with running balance",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-postedAt",
                "postedAt"
              ],
              "default": "-postedAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "postedFrom": {
                  "type": "string",
                  "format": "date-time"
                },
                "postedTo": {
                  "type": "string",
                  "format": "date-time"
                },
                "kind": {
                  "type": "string",
                  "description": "Comma-separated JournalEntryKind."
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JournalLinePage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/balances/{balanceId}/statements": {
      "get": {
        "operationId": "listStatements",
        "tags": [
          "accounts"
        ],
        "summary": "Monthly statements",
        "description": "**API key scope:** `statements:read`.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-periodStart",
                "periodStart"
              ],
              "default": "-periodStart"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "year": {
                  "type": "integer",
                  "minimum": 2000,
                  "maximum": 2100
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatementPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "statements:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "statements:read"
        ]
      },
      "post": {
        "operationId": "requestStatement",
        "tags": [
          "accounts"
        ],
        "summary": "Generate a custom-period statement (async)",
        "description": "**Step-up:** requires a verified step-up challenge for action `statement.full_export` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**API key scope:** `statements:read`.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StatementRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "statements:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "statements:read"
        ]
      }
    },
    "/balances/{balanceId}/statements/{statementId}/download": {
      "get": {
        "operationId": "downloadStatement",
        "tags": [
          "accounts"
        ],
        "summary": "Download statement",
        "description": "**API key scope:** `statements:read`.",
        "parameters": [
          {
            "name": "balanceId",
            "in": "path",
            "required": true,
            "description": "Identifier (balanceId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "statementId",
            "in": "path",
            "required": true,
            "description": "Identifier (statementId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "File format.",
            "schema": {
              "$ref": "#/components/schemas/ExportFormat"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DownloadLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "statements:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "statements:read"
        ]
      }
    },
    "/bulk-payments": {
      "get": {
        "operationId": "listBulkPayments",
        "tags": [
          "payments"
        ],
        "summary": "List bulk uploads",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPaymentPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createBulkPayment",
        "tags": [
          "payments"
        ],
        "summary": "Upload bulk payments file for validation",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkPaymentCreate"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/bulk-payments/{bulkPaymentId}": {
      "get": {
        "operationId": "getBulkPayment",
        "tags": [
          "payments"
        ],
        "summary": "Bulk upload status",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "bulkPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (bulkPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPayment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/bulk-payments/{bulkPaymentId}/cancel": {
      "post": {
        "operationId": "cancelBulkPayment",
        "tags": [
          "payments"
        ],
        "summary": "Cancel bulk upload",
        "description": "**API key scope:** `payments:write`.\n\n**Stalled submissions (re-review R-05):** a batch in `submitting` whose background run has stopped (no progress for two minutes) can be cancelled: rows not yet submitted become `failed` with code `cancelled`, payments already created stay and the batch ends `submitted` / `partially_submitted` (or `cancelled` when none was created, which also closes its batch approval). A batch that is still progressing answers `409 not-cancellable`. Batches that stay stalled are closed by the platform after 30 minutes (row code `submission_stalled`), and rows not yet submitted when the batch approval expires fail with code `approval_expired`.",
        "parameters": [
          {
            "name": "bulkPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (bulkPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPayment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/bulk-payments/{bulkPaymentId}/rows": {
      "get": {
        "operationId": "listBulkPaymentRows",
        "tags": [
          "payments"
        ],
        "summary": "Per-row validation results",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "bulkPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (bulkPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "row"
              ],
              "default": "row"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "enum": [
                    "valid",
                    "invalid",
                    "submitted",
                    "failed"
                  ]
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPaymentRowPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/bulk-payments/{bulkPaymentId}/submit": {
      "post": {
        "operationId": "submitBulkPayment",
        "tags": [
          "payments"
        ],
        "summary": "Submit validated rows as payments",
        "description": "Asynchronous (scalability audit X-12): moves the batch to `submitting`, opens the batch approval when the total falls in an approval tier, and returns `202` with the job (`Location: /v1/jobs/{jobId}`). Every valid row then becomes a payment through the single-payment path, each with its row status in one transaction, so an interrupted run resumes without duplicates. Submitting a batch that is already `submitting` returns the same job (and resumes it when it stalled, for the original submitter). `429 rate-limited` when too many batches of the operator are being submitted. Decisions on the batch approval are refused (`409`) until the batch leaves `submitting`.\n\n**Step-up:** requires a verified step-up challenge for action `payment.above_threshold` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.\n\n**Expired batch approval (re-review R-05):** re-submitting a batch in `submitting` whose batch approval is no longer pending answers `409 invalid-transition`; the remaining rows are closed as `failed` (`approval_expired`).",
        "parameters": [
          {
            "name": "bulkPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (bulkPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPaymentSubmitAccepted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/collections": {
      "get": {
        "operationId": "listCollections",
        "tags": [
          "payments"
        ],
        "summary": "List direct debit collections",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-dueDate",
                "dueDate"
              ],
              "default": "-dueDate"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "mandateId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "status": {
                  "type": "string"
                },
                "dueFrom": {
                  "type": "string",
                  "format": "date"
                },
                "dueTo": {
                  "type": "string",
                  "format": "date"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createCollection",
        "tags": [
          "payments"
        ],
        "summary": "Request a collection on a mandate",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectionCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Collection"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/collections/{collectionId}": {
      "get": {
        "operationId": "getCollection",
        "tags": [
          "payments"
        ],
        "summary": "Get collection",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "collectionId",
            "in": "path",
            "required": true,
            "description": "Identifier (collectionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Collection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/collections/{collectionId}/cancel": {
      "post": {
        "operationId": "cancelCollection",
        "tags": [
          "payments"
        ],
        "summary": "Cancel collection (before submission)",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "collectionId",
            "in": "path",
            "required": true,
            "description": "Identifier (collectionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Collection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/currencies": {
      "get": {
        "operationId": "listCurrencies",
        "tags": [
          "accounts"
        ],
        "summary": "Currencies offered by the operator (with enabled flag)",
        "description": "**API key scope:** `balances:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "enabled",
            "in": "query",
            "required": false,
            "description": "Only enabled for the customer tenant.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Currency"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/customers": {
      "get": {
        "operationId": "listCustomers",
        "tags": [
          "tenants"
        ],
        "summary": "List customers (operator)",
        "description": "**API key scope:** `customers:read` (operator-level keys only, `X-Tenant-Id` = the operator id).\n\n**Metadata filter:** `filter[metadata.<key>]=<value>` (exact match; at most 5; AND).\n\n**Batch look-up (P12-T07):** `filter[id]=<id>,<id>,…` (at most 100) returns those rows only, e.g. to resolve names shown next to ids; combine with `limit` ≥ the number of ids.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt",
                "legalName",
                "-legalName",
                "number"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date). P10-T03: `filter[metadata.<key>]=<value>` matches a metadata attribute exactly (key `[A-Za-z0-9_-]{1,40}`; at most 5 per request, AND-combined, one value each).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "description": "Comma-separated CustomerStatus values."
                },
                "risk": {
                  "type": "string",
                  "description": "Comma-separated RiskRating values."
                },
                "identityType": {
                  "$ref": "#/components/schemas/IdentityType"
                },
                "createdFrom": {
                  "type": "string",
                  "format": "date-time"
                },
                "createdTo": {
                  "type": "string",
                  "format": "date-time"
                },
                "customerType": {
                  "type": "string",
                  "description": "Comma-separated CustomerType values."
                },
                "id": {
                  "type": "string",
                  "description": "P12-T07: comma-separated ids (at most 100): the batch id → name look-up of the pickers (`400 too_many_filter_values` above the cap). Unknown or foreign ids are simply absent."
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          {
            "name": "withTotal",
            "in": "query",
            "required": false,
            "description": "Include `page.total` (may be slower). Computed on the first page only (a request without `cursor`); later pages omit `page.total` (scalability audit X-32).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "customers:read"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-api-key-scopes": [
          "customers:read"
        ]
      },
      "post": {
        "operationId": "createCustomer",
        "tags": [
          "tenants"
        ],
        "summary": "Create a customer (operator-initiated)",
        "description": "Creates a `draft` customer. With `primaryOwner` a primary-owner invitation is emailed; without it (console sessions only) no invitation is sent. Creates a draft customer and invites the primary owner. Self-registration uses `/auth/register`.\n\n**API key scope:** `customers:write` (operator-level keys only, `X-Tenant-Id` = the operator id).\n\n**API keys (review W3-02):** an operator key needs `customers:write`, the owner address must be on the operator settings' `apiKeyInvitationDomains` (`422 invitation_domains_required` / `domain_not_approved` before anything is written) and each key may create 10 customers a minute (`429`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "customers:write"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-idempotency": "optional",
        "x-api-key-scopes": [
          "customers:write"
        ]
      }
    },
    "/customers/{customerId}": {
      "get": {
        "operationId": "getCustomer",
        "tags": [
          "tenants"
        ],
        "summary": "Get customer",
        "description": "`X-Tenant-Id` is the customer itself or its operator. `customer.view` is held by operator staff roles and by every customer role (own customer only).\n\n**API key scope:** `customers:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "description": "Identifier (customerId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "customers:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "customers:read"
        ]
      }
    },
    "/customers/{customerId}/kyb": {
      "get": {
        "operationId": "getKybCase",
        "tags": [
          "onboarding"
        ],
        "summary": "Get KYB case (wizard state)",
        "description": "**API key scope:** `onboarding:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "description": "Identifier (customerId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KybCase"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "onboarding:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "onboarding:read"
        ]
      }
    },
    "/customers/{customerId}/settings/currencies": {
      "get": {
        "operationId": "listCustomerCurrencies",
        "tags": [
          "tenants"
        ],
        "summary": "Account currencies (offered and enabled)",
        "description": "**API key scope:** `balances:read`.",
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "description": "Identifier (customerId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CurrencySetting"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/developer/workspace": {
      "get": {
        "operationId": "getDeveloperWorkspace",
        "tags": [
          "developer"
        ],
        "summary": "My developer sandbox workspace",
        "description": "`404` when the customer is not a developer workspace. Records activity (the 90-day idle clock restarts).\n\n**API key scope:** `balances:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeveloperWorkspace"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/exchanges": {
      "get": {
        "operationId": "listExchanges",
        "tags": [
          "payments"
        ],
        "summary": "List exchanges",
        "description": "**API key scope:** `exchanges:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "description": "Comma-separated ExchangeKind."
                },
                "status": {
                  "type": "string"
                },
                "currency": {
                  "type": "string"
                },
                "createdFrom": {
                  "type": "string",
                  "format": "date-time"
                },
                "createdTo": {
                  "type": "string",
                  "format": "date-time"
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExchangePage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:read"
        ]
      },
      "post": {
        "operationId": "createExchange",
        "tags": [
          "payments"
        ],
        "summary": "Execute exchange from a quote",
        "description": "Exchanges are subject to payment approval policies when enabled.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExchangeCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exchange"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/exchanges/{exchangeId}": {
      "get": {
        "operationId": "getExchange",
        "tags": [
          "payments"
        ],
        "summary": "Get exchange",
        "description": "**API key scope:** `exchanges:read`.",
        "parameters": [
          {
            "name": "exchangeId",
            "in": "path",
            "required": true,
            "description": "Identifier (exchangeId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exchange"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:read"
        ]
      }
    },
    "/exchanges/{exchangeId}/confirmation": {
      "get": {
        "operationId": "getExchangeConfirmation",
        "tags": [
          "payments"
        ],
        "summary": "Exchange order confirmation (PDF)",
        "description": "The branded confirmation PDF, rendered on first request and cached (same behaviour as `GET /payments/{paymentId}/confirmation`).\n\n**API key scope:** `statements:read`.",
        "parameters": [
          {
            "name": "exchangeId",
            "in": "path",
            "required": true,
            "description": "Identifier (exchangeId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/pdf"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "statements:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "statements:read"
        ]
      }
    },
    "/exchanges/quotes": {
      "post": {
        "operationId": "createQuote",
        "tags": [
          "payments"
        ],
        "summary": "Create FX quote",
        "description": "**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/exchanges/quotes/{quoteId}": {
      "get": {
        "operationId": "getQuote",
        "tags": [
          "payments"
        ],
        "summary": "Get quote",
        "description": "**API key scope:** `exchanges:read`.",
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "Identifier (quoteId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:read"
        ]
      }
    },
    "/exchanges/quotes/{quoteId}/refresh": {
      "post": {
        "operationId": "refreshQuote",
        "tags": [
          "payments"
        ],
        "summary": "Refresh an expired quote (new quote, same terms)",
        "description": "**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "Identifier (quoteId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/forward-contracts": {
      "get": {
        "operationId": "listForwardContracts",
        "tags": [
          "payments"
        ],
        "summary": "List forward contracts and held rates",
        "description": "Forwards and held rates (`filter[kind]=held_rate`): there is no separate `/held-rates` resource; held rates are booked, listed and drawn down here.\n\n**Feature flag:** `fx.forwards`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `exchanges:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "settlementDate",
                "-settlementDate"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "forward",
                    "held_rate"
                  ]
                },
                "status": {
                  "type": "string"
                },
                "settlementFrom": {
                  "type": "string",
                  "format": "date"
                },
                "settlementTo": {
                  "type": "string",
                  "format": "date"
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExchangePage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:read"
        ]
      },
      "post": {
        "operationId": "createForwardContract",
        "tags": [
          "payments"
        ],
        "summary": "Book forward contract / held rate",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**Feature flag:** `fx.forwards`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForwardContractCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exchange"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/forward-contracts/{exchangeId}": {
      "get": {
        "operationId": "getForwardContract",
        "tags": [
          "payments"
        ],
        "summary": "Get forward contract",
        "description": "**Feature flag:** `fx.forwards`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `exchanges:read`.",
        "parameters": [
          {
            "name": "exchangeId",
            "in": "path",
            "required": true,
            "description": "Identifier (exchangeId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exchange"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:read"
        ]
      }
    },
    "/forward-contracts/{exchangeId}/deposit": {
      "post": {
        "operationId": "topUpForwardDeposit",
        "tags": [
          "payments"
        ],
        "summary": "Top up a forward deposit (margin call)",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**Feature flag:** `fx.forwards`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "name": "exchangeId",
            "in": "path",
            "required": true,
            "description": "Identifier (exchangeId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForwardDepositTopUp"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exchange"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/forward-contracts/{exchangeId}/drawdowns": {
      "post": {
        "operationId": "drawdownForwardContract",
        "tags": [
          "payments"
        ],
        "summary": "Draw down a forward contract",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**Feature flag:** `fx.forwards`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "name": "exchangeId",
            "in": "path",
            "required": true,
            "description": "Identifier (exchangeId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Drawdown"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exchange"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/forward-contracts/deposit-balance": {
      "get": {
        "operationId": "getForwardDepositBalance",
        "tags": [
          "payments"
        ],
        "summary": "Deposit balance held for forwards",
        "description": "**Feature flag:** `fx.forwards`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `exchanges:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositBalance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:read"
        ]
      }
    },
    "/funds-requests": {
      "get": {
        "operationId": "listFundsRequests",
        "tags": [
          "payments"
        ],
        "summary": "List funds requests",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string"
                },
                "balanceId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "mine": {
                  "type": "boolean"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundsRequestPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createFundsRequest",
        "tags": [
          "payments"
        ],
        "summary": "Request funds",
        "description": "`409 funds-requests-disabled` when the customer setting is off.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FundsRequestCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundsRequest"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/funds-requests/{fundsRequestId}": {
      "get": {
        "operationId": "getFundsRequest",
        "tags": [
          "payments"
        ],
        "summary": "Get funds request",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "fundsRequestId",
            "in": "path",
            "required": true,
            "description": "Identifier (fundsRequestId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundsRequest"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/funds-requests/{fundsRequestId}/cancel": {
      "post": {
        "operationId": "cancelFundsRequest",
        "tags": [
          "payments"
        ],
        "summary": "Cancel funds request",
        "description": "**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "fundsRequestId",
            "in": "path",
            "required": true,
            "description": "Identifier (fundsRequestId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundsRequest"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/integration": {
      "get": {
        "operationId": "getIntegrationHome",
        "tags": [
          "public-api"
        ],
        "summary": "Integration home: connections, webhooks, API keys, usage and portal links",
        "description": "Operator console \"Integration\" page (P9-T11, FR-PLAT-06): every non-retired banking connection with lifecycle, health, breaker, webhook registration and last event, event backlog, last reconciliation run and open exceptions, activation checklist progress; API key counts; 7-day usage; integrator webhook health; developer-portal links.\n\n**API key scope:** `integration:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationHome"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "integration:read"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-api-key-scopes": [
          "integration:read"
        ]
      }
    },
    "/integration/api-keys/{apiKeyId}/requests": {
      "get": {
        "operationId": "listOperatorApiKeyRequests",
        "tags": [
          "public-api"
        ],
        "summary": "Recent requests of an API key (7 days, no bodies)",
        "description": "The last requests of any key of the operator (newest first) and the status breakdown over 7 days. Method, route template, status, duration and request id only.\n\n**API key scope:** `integration:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "name": "apiKeyId",
            "in": "path",
            "required": true,
            "description": "Identifier (apiKeyId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Entries (default and max 100).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "required": false,
            "description": "`errors`: status 400 and above only.",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "errors"
              ],
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyRequestLog"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "integration:read"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-api-key-scopes": [
          "integration:read"
        ]
      }
    },
    "/integration/api-usage": {
      "get": {
        "operationId": "getOperatorApiUsage",
        "tags": [
          "public-api"
        ],
        "summary": "API usage per key across the operator (daily)",
        "description": "Per-key totals and daily series (P9-T11). Days before yesterday come from the daily rollup; yesterday and today are live from the request log (a call appears within `API_REQUEST_LOG_FLUSH_MS`, 5 s by default). Covers every key of the operator: customer keys and operator-level keys.\n\n**API key scope:** `integration:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First UTC day (default: `to` minus 6 days).",
            "schema": {
              "$ref": "#/components/schemas/Date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last UTC day, inclusive (default: today). At most 90 days after `from`.",
            "schema": {
              "$ref": "#/components/schemas/Date"
            }
          },
          {
            "name": "apiKeyId",
            "in": "query",
            "required": false,
            "description": "One key only.",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "environment",
            "in": "query",
            "required": false,
            "description": "`live` or `test` keys only.",
            "schema": {
              "type": "string",
              "enum": [
                "live",
                "test"
              ]
            }
          },
          {
            "name": "customerId",
            "in": "query",
            "required": false,
            "description": "One customer's keys only.",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiUsageReport"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "integration:read"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-api-key-scopes": [
          "integration:read"
        ]
      }
    },
    "/integrator-webhooks": {
      "get": {
        "operationId": "listIntegratorWebhooks",
        "tags": [
          "public-api"
        ],
        "summary": "List integrator webhook endpoints",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegratorWebhookPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      },
      "post": {
        "operationId": "createIntegratorWebhook",
        "tags": [
          "public-api"
        ],
        "summary": "Register webhook endpoint",
        "description": "Not idempotent: the response carries the signing secret shown once. SSRF guard on the URL (`422`); at most 10 endpoints per customer (`409`).\n\n**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).\n\n**Step-up:** requires a verified step-up challenge for action `integrator_webhook.change` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation. API keys holding `webhooks:manage` may call it without a step-up; every create, update, secret rotation and deletion notifies the endpoint owners (`webhook_endpoint_changed`, staff or customer members with `webhooks.manage`), whoever made it (review W3-03, P4 S-14).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorWebhookWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegratorWebhookCreated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/integrator-webhooks/{webhookId}": {
      "get": {
        "operationId": "getIntegratorWebhook",
        "tags": [
          "public-api"
        ],
        "summary": "Get webhook endpoint",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegratorWebhook"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      },
      "patch": {
        "operationId": "updateIntegratorWebhook",
        "tags": [
          "public-api"
        ],
        "summary": "Update webhook endpoint",
        "description": "**Concurrency:** `If-Match` with the current `ETag` is required (`428` if absent, `412` if stale).\n\n**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).\n\n**Step-up:** requires a verified step-up challenge for action `integrator_webhook.change` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation. API keys holding `webhooks:manage` may call it without a step-up; every create, update, secret rotation and deletion notifies the endpoint owners (`webhook_endpoint_changed`, staff or customer members with `webhooks.manage`), whoever made it (review W3-03, P4 S-14).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorWebhookWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegratorWebhook"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      },
      "delete": {
        "operationId": "deleteIntegratorWebhook",
        "tags": [
          "public-api"
        ],
        "summary": "Delete webhook endpoint",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).\n\n**Step-up:** requires a verified step-up challenge for action `integrator_webhook.change` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation. API keys holding `webhooks:manage` may call it without a step-up; every create, update, secret rotation and deletion notifies the endpoint owners (`webhook_endpoint_changed`, staff or customer members with `webhooks.manage`), whoever made it (review W3-03, P4 S-14).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/integrator-webhooks/{webhookId}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "public-api"
        ],
        "summary": "Delivery attempts",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "succeeded": {
                  "type": "boolean"
                },
                "eventType": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/integrator-webhooks/{webhookId}/deliveries/{deliveryId}/redeliver": {
      "post": {
        "operationId": "redeliverWebhook",
        "tags": [
          "public-api"
        ],
        "summary": "Redeliver an event",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "description": "Identifier (deliveryId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDelivery"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/integrator-webhooks/{webhookId}/rotate-secret": {
      "post": {
        "operationId": "rotateIntegratorWebhookSecret",
        "tags": [
          "public-api"
        ],
        "summary": "Rotate signing secret (old valid 24 h)",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).\n\n**Step-up:** requires a verified step-up challenge for action `integrator_webhook.change` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation. API keys holding `webhooks:manage` may call it without a step-up; every create, update, secret rotation and deletion notifies the endpoint owners (`webhook_endpoint_changed`, staff or customer members with `webhooks.manage`), whoever made it (review W3-03, P4 S-14).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegratorWebhookCreated"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/integrator-webhooks/{webhookId}/test": {
      "post": {
        "operationId": "testIntegratorWebhook",
        "tags": [
          "public-api"
        ],
        "summary": "Send a test event",
        "description": "**API key scope:** `webhooks:manage`.\n\n**Level (P9-T08b):** `X-Tenant-Id` = a customer → that customer's endpoints; `X-Tenant-Id` = the operator → the operator-level endpoints (sessions of operator owners with `webhooks.manage`, operator-level keys with `webhooks:manage`).",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "Identifier (webhookId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDelivery"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/jobs/{jobId}": {
      "get": {
        "operationId": "getJob",
        "tags": [
          "activity"
        ],
        "summary": "Get asynchronous job (exports, reports)",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "description": "Identifier (jobId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/mandates": {
      "get": {
        "operationId": "listMandates",
        "tags": [
          "payments"
        ],
        "summary": "List direct debit mandates",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "direction": {
                  "$ref": "#/components/schemas/MandateDirection"
                },
                "scheme": {
                  "$ref": "#/components/schemas/MandateScheme"
                },
                "status": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MandatePage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createMandate",
        "tags": [
          "payments"
        ],
        "summary": "Create mandate",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MandateCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mandate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/mandates/{mandateId}": {
      "get": {
        "operationId": "getMandate",
        "tags": [
          "payments"
        ],
        "summary": "Get mandate",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "mandateId",
            "in": "path",
            "required": true,
            "description": "Identifier (mandateId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mandate"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/mandates/{mandateId}/cancel": {
      "post": {
        "operationId": "cancelMandate",
        "tags": [
          "payments"
        ],
        "summary": "Cancel mandate",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "mandateId",
            "in": "path",
            "required": true,
            "description": "Identifier (mandateId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mandate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/mandates/{mandateId}/schedules": {
      "get": {
        "operationId": "listMandateSchedules",
        "tags": [
          "payments"
        ],
        "summary": "Collection schedules of a mandate",
        "description": "Activate, deactivate or end them through `/scheduled-payments/{scheduledPaymentId}`.\n\n**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "mandateId",
            "in": "path",
            "required": true,
            "description": "Identifier (mandateId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ScheduledPayment"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createMandateSchedule",
        "tags": [
          "payments"
        ],
        "summary": "Create a collection schedule",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "mandateId",
            "in": "path",
            "required": true,
            "description": "Identifier (mandateId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectionScheduleCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/mandates/{mandateId}/sign": {
      "post": {
        "operationId": "signMandate",
        "tags": [
          "payments"
        ],
        "summary": "Record the mandate signature",
        "description": "**Feature flag:** `payments.direct_debits`; returns `404` with problem type `feature-disabled` when the flag is off for the operator.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "mandateId",
            "in": "path",
            "required": true,
            "description": "Identifier (mandateId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MandateSign"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mandate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/payments": {
      "get": {
        "operationId": "listPayments",
        "tags": [
          "payments"
        ],
        "summary": "List payments",
        "description": "**API key scope:** `payments:read`.\n\n**Metadata filter:** `filter[metadata.<key>]=<value>` (exact match; at most 5; AND).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date). P10-T03: `filter[metadata.<key>]=<value>` matches a metadata attribute exactly (key `[A-Za-z0-9_-]{1,40}`; at most 5 per request, AND-combined, one value each).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "description": "Comma-separated PaymentStatus."
                },
                "kind": {
                  "type": "string",
                  "description": "Comma-separated PaymentKind."
                },
                "rail": {
                  "type": "string"
                },
                "recipientId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "sourceBalanceId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "currency": {
                  "type": "string"
                },
                "channel": {
                  "type": "string"
                },
                "createdFrom": {
                  "type": "string",
                  "format": "date-time"
                },
                "createdTo": {
                  "type": "string",
                  "format": "date-time"
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createPayment",
        "tags": [
          "payments"
        ],
        "summary": "Create payment (single-payment wizard)",
        "description": "Validates limits and balance, computes fees, places a hold, applies approval tiers (→ `pending_approval`) or routes and submits. **Conditional step-up:** `x-step-up` names `payment.first_to_recipient`, but the requirement is evaluated after validation: the first payment to a recipient needs `payment.first_to_recipient`, a payment at or above the threshold (customer `settings.payments.stepUpThreshold`, else operator `payments.stepUpThreshold`) needs `payment.above_threshold`; drafts (`submit: false`) need none. `POST /payments/dry-run` returns `requiresStepUp` / `stepUpAction`. API-key requests skip step-up but are always subject to approval tiers (D-24). Recipient must be `approved`. Cross-currency payments (`amount.currency` ≠ source currency) need a live spot `quoteId` selling the source currency for exactly `amount` (`422 quote_required` / `quote_mismatch`, `409 quote-expired`); the conversion executes before submission.\n\n**Step-up:** requires a verified step-up challenge for action `payment.first_to_recipient` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentCreate"
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
                    "recipientId": "0192a6f1-2222-7000-8000-00000000a001",
                    "amount": {
                      "amountMinor": "100000",
                      "currency": "EUR"
                    },
                    "fixedSide": "buy",
                    "quoteId": "0192a6f1-4444-7000-8000-00000000d001",
                    "reference": "INV-2026-0042",
                    "submit": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/payments/{paymentId}": {
      "get": {
        "operationId": "getPayment",
        "tags": [
          "payments"
        ],
        "summary": "Get payment",
        "description": "**API key scope:** `payments:read`.\n\n**Processing with ETA (D-50):** while an approved payment waits in the submission queue behind other payments of the operator, `processing` gives its queue position and an estimated hand-off time; it is absent once the payment is submitted (and for scheduled payments before their execution date).",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "patch": {
        "operationId": "updatePaymentDraft",
        "tags": [
          "payments"
        ],
        "summary": "Edit draft payment",
        "description": "**Concurrency:** `If-Match` with the current `ETag` is required (`428` if absent, `412` if stale).\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/payments/{paymentId}/cancel": {
      "post": {
        "operationId": "cancelPayment",
        "tags": [
          "payments"
        ],
        "summary": "Cancel payment (before submission)",
        "description": "Allowed in `draft`, `pending_approval`, `approved` and scheduled; releases the hold. After submission use a recall via operator support (`409 not-cancellable`).\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/payments/{paymentId}/confirmation": {
      "get": {
        "operationId": "getPaymentConfirmation",
        "tags": [
          "payments"
        ],
        "summary": "Payment order confirmation (PDF)",
        "description": "**API key scope:** `statements:read`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/pdf"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "statements:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "statements:read"
        ]
      }
    },
    "/payments/{paymentId}/events": {
      "get": {
        "operationId": "listPaymentEvents",
        "tags": [
          "payments"
        ],
        "summary": "Payment status history",
        "description": "Payment timeline. **Operator staff** (`x-tenant: any`): with `X-Tenant-Id` set to a customer they read that customer; with their operator id they read every customer of the operator (RLS operator scope); `404` when the payment is outside the tenant.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PaymentEvent"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/payments/{paymentId}/submit": {
      "post": {
        "operationId": "submitPayment",
        "tags": [
          "payments"
        ],
        "summary": "Submit draft payment",
        "description": "Same checks as a direct submit; step-up is conditional as on `createPayment` (`payment.first_to_recipient` or `payment.above_threshold`).\n\n**Step-up:** requires a verified step-up challenge for action `payment.first_to_recipient` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/payments/dry-run": {
      "post": {
        "operationId": "dryRunPayment",
        "tags": [
          "payments"
        ],
        "summary": "Preview fees, rate, route and checks",
        "description": "**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentDryRun"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/payments/purpose-codes": {
      "get": {
        "operationId": "listPurposeCodes",
        "tags": [
          "payments"
        ],
        "summary": "Purpose codes for a payment",
        "description": "Purpose / transfer-reason catalogue (P10-T03, FR-PAY-13, parity P-50) for a currency, destination and rail: the accepted codes and whether one is required. Payment creation applies the same rule.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "currency",
            "in": "query",
            "required": true,
            "description": "Payment currency.",
            "schema": {
              "$ref": "#/components/schemas/CurrencyCode"
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Bank country of the recipient.",
            "schema": {
              "$ref": "#/components/schemas/CountryCode"
            }
          },
          {
            "name": "rail",
            "in": "query",
            "required": false,
            "description": "Rail, when known.",
            "schema": {
              "$ref": "#/components/schemas/Rail"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurposeCodeCatalogue"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "any",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/provider-connections": {
      "get": {
        "operationId": "listProviderConnections",
        "tags": [
          "providers"
        ],
        "summary": "List provider connections",
        "description": "**API key scope:** `integration:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "provider": {
                  "type": "string"
                },
                "environment": {
                  "$ref": "#/components/schemas/ProviderEnvironment"
                },
                "status": {
                  "$ref": "#/components/schemas/ConnectionLifecycle"
                },
                "customerId": {
                  "$ref": "#/components/schemas/Uuid"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConnectionPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "integration:read"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-api-key-scopes": [
          "integration:read"
        ]
      }
    },
    "/provider-connections/{connectionId}": {
      "get": {
        "operationId": "getProviderConnection",
        "tags": [
          "providers"
        ],
        "summary": "Get provider connection (no secrets)",
        "description": "**API key scope:** `integration:read` (operator-level keys only, `X-Tenant-Id` = the operator id).",
        "parameters": [
          {
            "name": "connectionId",
            "in": "path",
            "required": true,
            "description": "Identifier (connectionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConnection"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "integration:read"
            ]
          }
        ],
        "x-tenant": "operator",
        "x-api-key-scopes": [
          "integration:read"
        ]
      }
    },
    "/recipients": {
      "get": {
        "operationId": "listRecipients",
        "tags": [
          "recipients"
        ],
        "summary": "List recipients",
        "description": "**API key scope:** `recipients:read`.\n\n**Metadata filter:** `filter[metadata.<key>]=<value>` (exact match; at most 5; AND).\n\n**Batch look-up (P12-T07):** `filter[id]=<id>,<id>,…` (at most 100) returns those rows only, e.g. to resolve names shown next to ids; combine with `limit` ≥ the number of ids.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "-name",
                "-lastPaidAt",
                "-createdAt"
              ],
              "default": "name"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date). P10-T03: `filter[metadata.<key>]=<value>` matches a metadata attribute exactly (key `[A-Za-z0-9_-]{1,40}`; at most 5 per request, AND-combined, one value each).",
            "schema": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string"
                },
                "bankCountry": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "description": "Comma-separated RecipientStatus."
                },
                "type": {
                  "$ref": "#/components/schemas/RecipientType"
                },
                "recent": {
                  "type": "boolean",
                  "description": "Recently paid (Payments hub)."
                },
                "id": {
                  "type": "string",
                  "description": "P12-T07: comma-separated ids (at most 100): the batch id → name look-up of the pickers (`400 too_many_filter_values` above the cap). Unknown or foreign ids are simply absent."
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          {
            "name": "withTotal",
            "in": "query",
            "required": false,
            "description": "Include `page.total` (may be slower). P12-T07: `limit=1&withTotal=true` is the count-only form for badges.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecipientPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:read"
        ]
      },
      "post": {
        "operationId": "createRecipient",
        "tags": [
          "recipients"
        ],
        "summary": "Add recipient",
        "description": "Validates against requirements (IBAN mod-97, BIC, national formats), de-duplicates (`409 duplicate-recipient`), runs CoP/VoP where available and applies the approval mode (D-14): customer approval tier or operator queue. API keys: no step-up; recipients created by API keys always require approval by a human per the customer policy.\n\n**Step-up:** requires a verified step-up challenge for action `recipient.create` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `recipients:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecipientCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Recipient"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/recipients/{recipientId}": {
      "get": {
        "operationId": "getRecipient",
        "tags": [
          "recipients"
        ],
        "summary": "Get recipient (full details)",
        "description": "**API key scope:** `recipients:read`.",
        "parameters": [
          {
            "name": "recipientId",
            "in": "path",
            "required": true,
            "description": "Identifier (recipientId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Recipient"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:read"
        ]
      },
      "patch": {
        "operationId": "updateRecipient",
        "tags": [
          "recipients"
        ],
        "summary": "Edit recipient",
        "description": "**Step-up:** requires a verified step-up challenge for action `recipient.update` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**Concurrency:** `If-Match` with the current `ETag` is required (`428` if absent, `412` if stale).\n\n**API key scope:** `recipients:write`.",
        "parameters": [
          {
            "name": "recipientId",
            "in": "path",
            "required": true,
            "description": "Identifier (recipientId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecipientUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Recipient"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:write"
        ]
      },
      "delete": {
        "operationId": "deleteRecipient",
        "tags": [
          "recipients"
        ],
        "summary": "Delete recipient (soft)",
        "description": "`409` if scheduled payments or pending payments reference it.\n\n**Concurrency:** `If-Match` with the current `ETag` is required (`428` if absent, `412` if stale).\n\n**API key scope:** `recipients:write`.",
        "parameters": [
          {
            "name": "recipientId",
            "in": "path",
            "required": true,
            "description": "Identifier (recipientId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:write"
        ]
      }
    },
    "/recipients/{recipientId}/verify": {
      "post": {
        "operationId": "verifyRecipient",
        "tags": [
          "recipients"
        ],
        "summary": "Run Confirmation / Verification of Payee",
        "description": "`422 verification-unavailable` if no routed provider supports CoP/VoP for this currency/country.\n\n**API key scope:** `recipients:write`.",
        "parameters": [
          {
            "name": "recipientId",
            "in": "path",
            "required": true,
            "description": "Identifier (recipientId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecipientVerification"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:write"
        ]
      }
    },
    "/recipients/requirements": {
      "get": {
        "operationId": "getRecipientRequirements",
        "tags": [
          "recipients"
        ],
        "summary": "Field requirements per currency and country",
        "description": "**API key scope:** `recipients:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "currency",
            "in": "query",
            "required": true,
            "description": "Recipient currency.",
            "schema": {
              "$ref": "#/components/schemas/CurrencyCode"
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": true,
            "description": "Bank country.",
            "schema": {
              "$ref": "#/components/schemas/CountryCode"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Recipient type.",
            "schema": {
              "$ref": "#/components/schemas/RecipientType"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecipientRequirements"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "recipients:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "recipients:read"
        ]
      }
    },
    "/sandbox/incoming-payments": {
      "post": {
        "operationId": "simulateSandboxIncomingPayment",
        "tags": [
          "public-api"
        ],
        "summary": "Simulate an incoming payment",
        "description": "Sandbox only (`wb_test_` keys and sandbox environments); `404 feature-disabled` elsewhere.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxIncomingPayment"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxSimulation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/sandbox/payments/{paymentId}/status": {
      "post": {
        "operationId": "simulateSandboxPaymentStatus",
        "tags": [
          "public-api"
        ],
        "summary": "Simulate a provider status for a payment",
        "description": "Sandbox only (`wb_test_` keys and sandbox environments); `404 feature-disabled` elsewhere.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxPaymentStatus"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxSimulation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/sandbox/reset": {
      "post": {
        "operationId": "resetSandbox",
        "tags": [
          "public-api"
        ],
        "summary": "Reset sandbox deliveries and paused endpoints",
        "description": "Sandbox only (`wb_test_` keys and sandbox environments); `404 feature-disabled` elsewhere.\n\n**API key scope:** `webhooks:manage`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxReset"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "webhooks:manage"
        ]
      }
    },
    "/sandbox/webhook-events": {
      "post": {
        "operationId": "simulateSandboxWebhookEvent",
        "tags": [
          "public-api"
        ],
        "summary": "Emit an integrator event",
        "description": "Sandbox only (`wb_test_` keys and sandbox environments); `404 feature-disabled` elsewhere. Events carry `data.sandbox: true`.\n\n**API key scope:** `webhooks:manage`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxWebhookEvent"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxSimulation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "webhooks:manage"
        ],
        "x-idempotency": "optional"
      }
    },
    "/scheduled-payments": {
      "get": {
        "operationId": "listScheduledPayments",
        "tags": [
          "payments"
        ],
        "summary": "List scheduled payments (Active / Inactive)",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "nextRunAt",
                "-createdAt"
              ],
              "default": "nextRunAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "description": "Comma-separated ScheduledPaymentStatus."
                },
                "recipientId": {
                  "$ref": "#/components/schemas/Uuid"
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "withTotal",
            "in": "query",
            "required": false,
            "description": "Include `page.total` (may be slower). Computed on the first page only (a request without `cursor`); later pages omit `page.total` (scalability audit X-32).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPaymentPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "Create scheduled payment / standing order",
        "description": "**Step-up:** requires a verified step-up challenge for action `payment.first_to_recipient` within the last 5 minutes (session/bearer only). Otherwise `403` with problem type `step-up-required`; the step-up check runs before body validation.\n\n**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduledPaymentWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/scheduled-payments/{scheduledPaymentId}": {
      "get": {
        "operationId": "getScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "Get scheduled payment",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPayment"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "patch": {
        "operationId": "updateScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "Edit scheduled payment",
        "description": "**Concurrency:** `If-Match` with the current `ETag` is required (`428` if absent, `412` if stale).\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduledPaymentWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      },
      "delete": {
        "operationId": "deleteScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "End scheduled payment",
        "description": "**Concurrency:** `If-Match` with the current `ETag` is required (`428` if absent, `412` if stale).\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/scheduled-payments/{scheduledPaymentId}/activate": {
      "post": {
        "operationId": "activateScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "Reactivate",
        "description": "**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPayment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/scheduled-payments/{scheduledPaymentId}/deactivate": {
      "post": {
        "operationId": "deactivateScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "Deactivate",
        "description": "**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledPayment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ]
      }
    },
    "/scheduled-payments/{scheduledPaymentId}/occurrences": {
      "get": {
        "operationId": "listScheduledPaymentOccurrences",
        "tags": [
          "payments"
        ],
        "summary": "Upcoming and past runs",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Upcoming runs to plan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 60,
              "default": 12
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledOccurrences"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/scheduled-payments/preview": {
      "post": {
        "operationId": "previewScheduledPayment",
        "tags": [
          "payments"
        ],
        "summary": "Preview the runs of a schedule",
        "description": "Canonical RRULE and the next runs (nominal and execution dates, run instant). No writes.\n\n**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SchedulePreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SchedulePreview"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    },
    "/simulations": {
      "get": {
        "operationId": "listSimulations",
        "tags": [
          "simulations"
        ],
        "summary": "Available simulations and sandbox rules",
        "description": "**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `balances:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationCatalogue"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "balances:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "balances:read"
        ]
      }
    },
    "/simulations/cards/{cardId}/transactions": {
      "post": {
        "operationId": "simulateCardTransaction",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate a card transaction event",
        "description": "A neutral card event (`cards/transaction`) as the card processor would send it: authorisation (hold), settlement, reversal, refund or decline.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "cardId",
            "in": "path",
            "required": true,
            "description": "Identifier (cardId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimCardTransaction"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/direct-debits/collections/{collectionId}/status": {
      "post": {
        "operationId": "simulateCollectionStatus",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate a direct-debit collection outcome",
        "description": "**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "collectionId",
            "in": "path",
            "required": true,
            "description": "Identifier (collectionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimCollectionStatus"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/exchanges/{exchangeId}/status": {
      "post": {
        "operationId": "simulateExchangeStatus",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate the settlement of an exchange",
        "description": "Applies to an exchange still `processing` at the sandbox bank.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "name": "exchangeId",
            "in": "path",
            "required": true,
            "description": "Identifier (exchangeId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimExchangeStatus"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/fx-rates": {
      "post": {
        "operationId": "simulateFxRateMove",
        "tags": [
          "simulations"
        ],
        "summary": "Move a sandbox FX rate",
        "description": "Stored on the operator's sandbox connection (`rateShiftsBps`): every quote of the pair moves (the inverse pair the other way). `applied`; `details.rate` is the new rate.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `exchanges:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimFxRate"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "exchanges:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "exchanges:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/incoming-debits": {
      "post": {
        "operationId": "simulateIncomingDebit",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate a direct debit taken from a balance",
        "description": "Banking Circle sandbox only (`POST /api/v1/payments/simulations/debits`); `409` on other connections.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimIncomingDebit"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/incoming-payments": {
      "post": {
        "operationId": "simulateIncomingPayment",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate an incoming payment",
        "description": "Sandbox bank: an `account.credited` event through the webhook pipeline (`queued`). Banking Circle sandbox: `POST /api/v1/payments/simulations/credits` on the balance account (`submitted`; the `IncomingPaymentProcessed` notification follows). Integrated Finance sandbox: a provisioned account credit on the balance IBAN (inferred until IF-33).\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimIncomingPayment"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/incoming-payments/{incomingPaymentId}/recall": {
      "post": {
        "operationId": "simulateIncomingRecall",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate an inbound recall request",
        "description": "Opens a partner compliance case (`inbound_recall`, provider `sandbox`) in the operator's queue (`applied`).\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "incomingPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (incomingPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimIncomingRecall"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/kyc": {
      "post": {
        "operationId": "simulateKycOutcome",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate a KYC review outcome",
        "description": "Applied as the KYC provider's `applicantReviewed` webhook: `approved` (GREEN), `rejected` (RED FINAL), `retry` (RED RETRY).\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimKycOutcome"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/payments/{paymentId}/recall": {
      "post": {
        "operationId": "simulatePaymentRecall",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate the outcome of a payment recall",
        "description": "`accepted`: the funds come back (a return with the recall reason); `rejected`: recorded on the provider event log, nothing moves.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimPaymentRecall"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/payments/{paymentId}/return": {
      "post": {
        "operationId": "simulatePaymentReturn",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate the return of a payment",
        "description": "**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimPaymentReturn"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/payments/{paymentId}/status": {
      "post": {
        "operationId": "simulatePaymentStatus",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate the provider status of a payment",
        "description": "A payment sent through the sandbox bank (`409` before it is sent or on a partner connection). The worker applies the stated status without asking the sandbox bank.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (paymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimPaymentStatus"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/provider-outage": {
      "post": {
        "operationId": "simulateProviderOutage",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate a sandbox bank outage",
        "description": "Bank calls fail with a retryable provider error until the time given (`applied`): rehearse retries and backoff.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimOutage"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/scheduled-payments/{scheduledPaymentId}/run-now": {
      "post": {
        "operationId": "simulateScheduledRun",
        "tags": [
          "simulations"
        ],
        "summary": "Run a scheduled payment now",
        "description": "An active schedule with a next occurrence is made due now and handed to the worker (`409` otherwise).\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "name": "scheduledPaymentId",
            "in": "path",
            "required": true,
            "description": "Identifier (scheduledPaymentId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/statements": {
      "post": {
        "operationId": "simulateStatement",
        "tags": [
          "simulations"
        ],
        "summary": "Simulate a statement becoming available",
        "description": "A `statement.available` integrator event for the balance.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `webhooks:manage`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimStatement"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "webhooks:manage"
        ],
        "x-idempotency": "optional"
      }
    },
    "/simulations/webhook-events": {
      "post": {
        "operationId": "simulateWebhookEvent",
        "tags": [
          "simulations"
        ],
        "summary": "Send an integrator event to your endpoints",
        "description": "Delivered to the customer's active endpoints subscribed to the type, with `data.sandbox: true`.\n\n**Sandbox only:** `404 feature-disabled` wherever the sandbox is off (always in production). Callers: a `wb_test_` API key of the customer, or a member session of a developer sandbox workspace (`403` for live keys and other sessions). Every simulation answers `202 SimulationResult`; `queued` outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.\n\n**API key scope:** `webhooks:manage`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimWebhookEvent"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "webhooks:manage"
        ],
        "x-idempotency": "optional"
      }
    },
    "/transactions": {
      "get": {
        "operationId": "listTransactions",
        "tags": [
          "activity"
        ],
        "summary": "List transactions (unified activity)",
        "description": "Server-side filtering and search (description, counterparty, reference, order id). Filters: date, status, type, balance, attachments, annotations (Equals Transactions screen).\n\n**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-postedAt",
                "postedAt",
                "-amount",
                "amount"
              ],
              "default": "-postedAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "dateFrom": {
                  "type": "string",
                  "format": "date"
                },
                "dateTo": {
                  "type": "string",
                  "format": "date"
                },
                "status": {
                  "type": "string",
                  "description": "Comma-separated TransactionStatus."
                },
                "type": {
                  "type": "string",
                  "description": "Comma-separated TransactionType."
                },
                "balanceId": {
                  "type": "string",
                  "description": "Comma-separated balance ids."
                },
                "currency": {
                  "type": "string"
                },
                "hasAttachments": {
                  "type": "boolean"
                },
                "hasAnnotations": {
                  "type": "boolean"
                },
                "label": {
                  "type": "string"
                },
                "amountMin": {
                  "$ref": "#/components/schemas/AmountMinor"
                },
                "amountMax": {
                  "$ref": "#/components/schemas/AmountMinor"
                },
                "direction": {
                  "type": "string",
                  "enum": [
                    "in",
                    "out"
                  ]
                },
                "counterparty": {
                  "type": "string",
                  "description": "Counterparty name contains (min 2 characters).",
                  "minLength": 2,
                  "maxLength": 100
                }
              },
              "additionalProperties": false
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (trigram; min 2 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          {
            "name": "withTotal",
            "in": "query",
            "required": false,
            "description": "Include `page.total` (may be slower). Computed on the first page only (a request without `cursor`); later pages omit `page.total` (scalability audit X-32).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/transactions/{transactionId}": {
      "get": {
        "operationId": "getTransaction",
        "tags": [
          "activity"
        ],
        "summary": "Transaction details (drawer: Details / Updates)",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "description": "Identifier (transactionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/transactions/{transactionId}/annotations": {
      "get": {
        "operationId": "listAnnotations",
        "tags": [
          "activity"
        ],
        "summary": "List annotations",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "description": "Identifier (transactionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Annotation"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/transactions/{transactionId}/attachments": {
      "get": {
        "operationId": "listTransactionAttachments",
        "tags": [
          "activity"
        ],
        "summary": "List attachments",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "description": "Identifier (transactionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Attachment"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/transactions/{transactionId}/confirmation": {
      "get": {
        "operationId": "getTransactionConfirmation",
        "tags": [
          "activity"
        ],
        "summary": "Order confirmation (PDF)",
        "description": "Account id, company address, order id, booking/settlement dates, from/to amounts, method, rate, total incl. fee, status, regulatory footer (Equals order confirmation).\n\n**API key scope:** `statements:read`.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "description": "Identifier (transactionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/pdf"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "statements:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "statements:read"
        ]
      }
    },
    "/transactions/{transactionId}/updates": {
      "get": {
        "operationId": "listTransactionUpdates",
        "tags": [
          "activity"
        ],
        "summary": "Status updates (Updates tab)",
        "description": "**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "description": "Identifier (transactionId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PaymentEvent"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/transactions/exports": {
      "post": {
        "operationId": "exportTransactions",
        "tags": [
          "activity"
        ],
        "summary": "Export statement or transaction activity (async)",
        "description": "Small exports may complete immediately (`Job.status=succeeded`). Full statement exports require step-up `statement.full_export` for interactive users.\n\n**API key scope:** `transactions:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "transactions:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "transactions:read"
        ]
      }
    },
    "/transfers": {
      "get": {
        "operationId": "listTransfers",
        "tags": [
          "payments"
        ],
        "summary": "List internal transfers",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order; prefix `-` for descending. Cursor stability is guaranteed only for the default sort.",
            "schema": {
              "type": "string",
              "enum": [
                "-createdAt",
                "createdAt"
              ],
              "default": "-createdAt"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "Filters as `filter[field]=value`. Multiple values for one field are comma-separated (OR); different fields combine with AND. Date ranges use `filter[createdFrom]`/`filter[createdTo]` (inclusive, RFC 3339 or date).",
            "schema": {
              "type": "object",
              "properties": {
                "balanceId": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "status": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      },
      "post": {
        "operationId": "createTransfer",
        "tags": [
          "payments"
        ],
        "summary": "Internal transfer between own balances",
        "description": "**Idempotency:** `Idempotency-Key` is required. Replays within 24 h return the original response with `Idempotency-Replayed: true`.\n\n**API key scope:** `payments:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransferCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transfer"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableContent"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:write"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:write"
        ],
        "x-idempotency": "required"
      }
    },
    "/transfers/{transferId}": {
      "get": {
        "operationId": "getTransfer",
        "tags": [
          "payments"
        ],
        "summary": "Get transfer",
        "description": "**API key scope:** `payments:read`.",
        "parameters": [
          {
            "name": "transferId",
            "in": "path",
            "required": true,
            "description": "Identifier (transferId).",
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "$ref": "#/components/parameters/TenantId"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transfer"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "security": [
          {
            "apiKey": [
              "payments:read"
            ]
          }
        ],
        "x-tenant": "customer",
        "x-api-key-scopes": [
          "payments:read"
        ]
      }
    }
  },
  "webhooks": {
    "payment.status_changed": {
      "post": {
        "operationId": "webhook_payment_status_changed",
        "tags": [
          "public-api"
        ],
        "summary": "Integrator callback: payment.status_changed",
        "description": "Delivered to registered integrator endpoints. Headers: `WireBloom-Event-Id`, `WireBloom-Event-Type`, `WireBloom-Timestamp` (unix seconds), `WireBloom-Signature: v1=<hex HMAC-SHA256(secret, timestamp + \".\" + rawBody)>` (several `v1=` values during secret rotation). Reject if the timestamp is older than 5 minutes; compare in constant time; de-duplicate on `WireBloom-Event-Id`. Respond `2xx` within 10 s; retries with exponential backoff for 72 h (1 m, 5 m, 30 m, 2 h, 6 h, then every 12 h); endpoint disabled after 72 h of failures.",
        "parameters": [
          {
            "name": "WireBloom-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "examples": [
                "v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ]
            }
          },
          {
            "name": "WireBloom-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            }
          },
          {
            "name": "WireBloom-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "WireBloom-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegratorEventType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged."
          },
          "default": {
            "description": "Any non-2xx triggers a retry."
          }
        },
        "security": []
      }
    },
    "incoming_payment.received": {
      "post": {
        "operationId": "webhook_incoming_payment_received",
        "tags": [
          "public-api"
        ],
        "summary": "Integrator callback: incoming_payment.received",
        "description": "Delivered to registered integrator endpoints. Headers: `WireBloom-Event-Id`, `WireBloom-Event-Type`, `WireBloom-Timestamp` (unix seconds), `WireBloom-Signature: v1=<hex HMAC-SHA256(secret, timestamp + \".\" + rawBody)>` (several `v1=` values during secret rotation). Reject if the timestamp is older than 5 minutes; compare in constant time; de-duplicate on `WireBloom-Event-Id`. Respond `2xx` within 10 s; retries with exponential backoff for 72 h (1 m, 5 m, 30 m, 2 h, 6 h, then every 12 h); endpoint disabled after 72 h of failures.",
        "parameters": [
          {
            "name": "WireBloom-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "examples": [
                "v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ]
            }
          },
          {
            "name": "WireBloom-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            }
          },
          {
            "name": "WireBloom-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "WireBloom-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegratorEventType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged."
          },
          "default": {
            "description": "Any non-2xx triggers a retry."
          }
        },
        "security": []
      }
    },
    "exchange.completed": {
      "post": {
        "operationId": "webhook_exchange_completed",
        "tags": [
          "public-api"
        ],
        "summary": "Integrator callback: exchange.completed",
        "description": "Delivered to registered integrator endpoints. Headers: `WireBloom-Event-Id`, `WireBloom-Event-Type`, `WireBloom-Timestamp` (unix seconds), `WireBloom-Signature: v1=<hex HMAC-SHA256(secret, timestamp + \".\" + rawBody)>` (several `v1=` values during secret rotation). Reject if the timestamp is older than 5 minutes; compare in constant time; de-duplicate on `WireBloom-Event-Id`. Respond `2xx` within 10 s; retries with exponential backoff for 72 h (1 m, 5 m, 30 m, 2 h, 6 h, then every 12 h); endpoint disabled after 72 h of failures.",
        "parameters": [
          {
            "name": "WireBloom-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "examples": [
                "v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ]
            }
          },
          {
            "name": "WireBloom-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            }
          },
          {
            "name": "WireBloom-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "WireBloom-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegratorEventType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged."
          },
          "default": {
            "description": "Any non-2xx triggers a retry."
          }
        },
        "security": []
      }
    },
    "recipient.status_changed": {
      "post": {
        "operationId": "webhook_recipient_status_changed",
        "tags": [
          "public-api"
        ],
        "summary": "Integrator callback: recipient.status_changed",
        "description": "Delivered to registered integrator endpoints. Headers: `WireBloom-Event-Id`, `WireBloom-Event-Type`, `WireBloom-Timestamp` (unix seconds), `WireBloom-Signature: v1=<hex HMAC-SHA256(secret, timestamp + \".\" + rawBody)>` (several `v1=` values during secret rotation). Reject if the timestamp is older than 5 minutes; compare in constant time; de-duplicate on `WireBloom-Event-Id`. Respond `2xx` within 10 s; retries with exponential backoff for 72 h (1 m, 5 m, 30 m, 2 h, 6 h, then every 12 h); endpoint disabled after 72 h of failures.",
        "parameters": [
          {
            "name": "WireBloom-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "examples": [
                "v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ]
            }
          },
          {
            "name": "WireBloom-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            }
          },
          {
            "name": "WireBloom-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "WireBloom-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegratorEventType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged."
          },
          "default": {
            "description": "Any non-2xx triggers a retry."
          }
        },
        "security": []
      }
    },
    "approval.requested": {
      "post": {
        "operationId": "webhook_approval_requested",
        "tags": [
          "public-api"
        ],
        "summary": "Integrator callback: approval.requested",
        "description": "Delivered to registered integrator endpoints. Headers: `WireBloom-Event-Id`, `WireBloom-Event-Type`, `WireBloom-Timestamp` (unix seconds), `WireBloom-Signature: v1=<hex HMAC-SHA256(secret, timestamp + \".\" + rawBody)>` (several `v1=` values during secret rotation). Reject if the timestamp is older than 5 minutes; compare in constant time; de-duplicate on `WireBloom-Event-Id`. Respond `2xx` within 10 s; retries with exponential backoff for 72 h (1 m, 5 m, 30 m, 2 h, 6 h, then every 12 h); endpoint disabled after 72 h of failures.",
        "parameters": [
          {
            "name": "WireBloom-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "examples": [
                "v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ]
            }
          },
          {
            "name": "WireBloom-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            }
          },
          {
            "name": "WireBloom-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "WireBloom-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegratorEventType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged."
          },
          "default": {
            "description": "Any non-2xx triggers a retry."
          }
        },
        "security": []
      }
    },
    "statement.available": {
      "post": {
        "operationId": "webhook_statement_available",
        "tags": [
          "public-api"
        ],
        "summary": "Integrator callback: statement.available",
        "description": "Delivered to registered integrator endpoints. Headers: `WireBloom-Event-Id`, `WireBloom-Event-Type`, `WireBloom-Timestamp` (unix seconds), `WireBloom-Signature: v1=<hex HMAC-SHA256(secret, timestamp + \".\" + rawBody)>` (several `v1=` values during secret rotation). Reject if the timestamp is older than 5 minutes; compare in constant time; de-duplicate on `WireBloom-Event-Id`. Respond `2xx` within 10 s; retries with exponential backoff for 72 h (1 m, 5 m, 30 m, 2 h, 6 h, then every 12 h); endpoint disabled after 72 h of failures.",
        "parameters": [
          {
            "name": "WireBloom-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "examples": [
                "v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ]
            }
          },
          {
            "name": "WireBloom-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            }
          },
          {
            "name": "WireBloom-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          {
            "name": "WireBloom-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegratorEventType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegratorEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged."
          },
          "default": {
            "description": "Any non-2xx triggers a retry."
          }
        },
        "security": []
      }
    }
  },
  "components": {
    "schemas": {
      "AccessStatus": {
        "type": "string",
        "enum": [
          "pending",
          "approved",
          "rejected"
        ],
        "description": "Access approval of a registration: grants or denies use of the app; never touches the banking partner, the ledger or the KYB case."
      },
      "AccountDetails": {
        "type": "object",
        "description": "Account details for one rail (Equals \"Account details\" modal: Local / SWIFT-Global toggle).",
        "properties": {
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "rail": {
            "type": "string",
            "enum": [
              "local",
              "swift"
            ]
          },
          "accountHolderName": {
            "type": "string",
            "examples": [
              "WireBloom Ltd"
            ]
          },
          "iban": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "GB33BUKB20201555555555"
            ]
          },
          "bic": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[A-Z0-9]{8}([A-Z0-9]{3})?$",
            "examples": [
              "SAPYGB2L"
            ]
          },
          "sortCode": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-9]{6}$",
            "examples": [
              "040075"
            ]
          },
          "accountNumber": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "12345678"
            ]
          },
          "routingCodes": {
            "type": "object",
            "description": "Other national codes (ABA, BSB, IFSC …) keyed by scheme.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "bankName": {
            "type": [
              "string",
              "null"
            ]
          },
          "bankAddress": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reference the payer must quote (pooled accounts)."
          },
          "virtual": {
            "type": "boolean"
          },
          "supportedRails": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Rail"
            }
          },
          "provider": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProviderId"
              }
            ],
            "readOnly": true
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "active"
            ],
            "description": "`pending` until the partner has provisioned the account (identifiers may still be null).",
            "readOnly": true
          }
        },
        "required": [
          "balanceId",
          "currency",
          "rail",
          "accountHolderName",
          "virtual",
          "supportedRails",
          "status"
        ]
      },
      "AccountStatus": {
        "type": "string",
        "enum": [
          "pending",
          "active",
          "on_hold",
          "closed"
        ]
      },
      "AddMoneyRequest": {
        "type": "object",
        "description": "`bank_transfer`: returns deposit details (Same currency). `conversion`: creates a conversion order from `fromBalanceId` at the locked `quoteId` rate (Convert currency).",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "bank_transfer",
              "conversion"
            ]
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PositiveMoney"
              },
              {
                "type": "null"
              }
            ]
          },
          "fromBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "quoteId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "fixedSide": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FixedSide"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "method",
          "balanceId"
        ],
        "additionalProperties": false,
        "examples": [
          {
            "method": "conversion",
            "balanceId": "0192a6f1-1111-7000-8000-00000000b003",
            "fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
            "amount": {
              "amountMinor": "250000",
              "currency": "EUR"
            },
            "fixedSide": "buy",
            "quoteId": "0192a6f1-4444-7000-8000-00000000d001"
          }
        ]
      },
      "AddMoneyResult": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "bank_transfer",
              "conversion"
            ]
          },
          "depositDetails": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/AccountDetails"
            }
          },
          "exchange": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Exchange"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "method"
        ]
      },
      "Address": {
        "type": "object",
        "description": "Structured postal address.",
        "properties": {
          "line1": {
            "type": "string",
            "maxLength": 140,
            "examples": [
              "1 Finsbury Avenue"
            ]
          },
          "line2": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          },
          "city": {
            "type": "string",
            "maxLength": 70,
            "examples": [
              "London"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 70
          },
          "postalCode": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 16,
            "examples": [
              "EC2M 2PF"
            ]
          },
          "country": {
            "$ref": "#/components/schemas/CountryCode"
          }
        },
        "required": [
          "line1",
          "city",
          "country"
        ]
      },
      "AmountMinor": {
        "type": "string",
        "description": "Signed integer amount in minor units of the currency (int64 encoded as a string to avoid precision loss).",
        "pattern": "^-?[0-9]{1,19}$",
        "examples": [
          "125050"
        ]
      },
      "Annotation": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "transactionId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          },
          "note": {
            "type": "string",
            "maxLength": 2000
          },
          "createdBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "createdByName": {
            "type": "string",
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "transactionId",
          "note",
          "createdBy",
          "createdAt"
        ]
      },
      "ApiKeyRequestLog": {
        "type": "object",
        "properties": {
          "apiKeyId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "retentionDays": {
            "type": "integer",
            "description": "Days the request log keeps (7).",
            "minimum": 1
          },
          "statusCounts": {
            "type": "object",
            "description": "Responses per HTTP status over the retention window (error breakdown).",
            "propertyNames": {
              "pattern": "^[1-5][0-9]{2}$"
            },
            "additionalProperties": {
              "type": "integer",
              "minimum": 0
            }
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiRequestLogEntry"
            },
            "description": "Newest first."
          }
        },
        "required": [
          "apiKeyId",
          "retentionDays",
          "statusCounts",
          "data"
        ]
      },
      "ApiKeyUsage": {
        "type": "object",
        "description": "Usage of one API key: totals and daily series. `customerId` null for operator-level keys (P9-T08b).",
        "properties": {
          "apiKeyId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string",
            "description": "Key prefix (`wb_live_…` / `wb_test_…`), never the secret."
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          },
          "customerId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "revokedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "lastRequestAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Latest request in the window.",
            "format": "date-time"
          },
          "totals": {
            "$ref": "#/components/schemas/ApiUsageTotals"
          },
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiUsageDay"
            },
            "description": "Days with requests, oldest first."
          }
        },
        "required": [
          "apiKeyId",
          "name",
          "prefix",
          "environment",
          "customerId",
          "customerName",
          "revokedAt",
          "lastUsedAt",
          "lastRequestAt",
          "totals",
          "days"
        ]
      },
      "ApiRequestLogEntry": {
        "type": "object",
        "description": "One request made with an API key. Never contains bodies, headers or query strings.",
        "properties": {
          "requestId": {
            "type": "string",
            "description": "`X-Request-Id` of the call."
          },
          "at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "method": {
            "type": "string",
            "examples": [
              "GET"
            ]
          },
          "route": {
            "type": "string",
            "description": "Matched route template (`/v1/payments/:paymentId`); `(unmatched)` for unknown paths."
          },
          "statusCode": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          },
          "durationMs": {
            "type": "integer",
            "minimum": 0
          },
          "rateLimited": {
            "type": "boolean"
          }
        },
        "required": [
          "requestId",
          "at",
          "method",
          "route",
          "statusCode",
          "durationMs",
          "rateLimited"
        ]
      },
      "ApiUsageDay": {
        "type": "object",
        "description": "One UTC day of one key. Days before yesterday come from the daily rollup (`api-usage.rollup`, every 15 minutes); yesterday and today are aggregated live from the request log.",
        "properties": {
          "date": {
            "$ref": "#/components/schemas/Date"
          },
          "requests": {
            "type": "integer",
            "minimum": 0
          },
          "clientErrors": {
            "type": "integer",
            "description": "Responses 400-499 other than 429.",
            "minimum": 0
          },
          "serverErrors": {
            "type": "integer",
            "description": "Responses 500-599.",
            "minimum": 0
          },
          "rateLimited": {
            "type": "integer",
            "description": "Responses 429 (`rate-limited`).",
            "minimum": 0
          },
          "errorRate": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "(clientErrors + serverErrors + rateLimited) / requests; null without requests."
          },
          "averageDurationMs": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Mean server time in milliseconds; null without requests."
          },
          "maxDurationMs": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "date",
          "requests",
          "clientErrors",
          "serverErrors",
          "rateLimited",
          "errorRate",
          "averageDurationMs",
          "maxDurationMs"
        ]
      },
      "ApiUsageReport": {
        "type": "object",
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Date"
          },
          "to": {
            "$ref": "#/components/schemas/Date"
          },
          "generatedAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "totals": {
            "$ref": "#/components/schemas/ApiUsageTotals"
          },
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKeyUsage"
            },
            "description": "Keys in scope (at most 200, newest first): active keys and keys revoked during the window, with or without requests."
          }
        },
        "required": [
          "from",
          "to",
          "generatedAt",
          "totals",
          "keys"
        ]
      },
      "ApiUsageTotals": {
        "type": "object",
        "description": "Request counts of API keys over a window.",
        "properties": {
          "requests": {
            "type": "integer",
            "minimum": 0
          },
          "clientErrors": {
            "type": "integer",
            "description": "Responses 400-499 other than 429.",
            "minimum": 0
          },
          "serverErrors": {
            "type": "integer",
            "description": "Responses 500-599.",
            "minimum": 0
          },
          "rateLimited": {
            "type": "integer",
            "description": "Responses 429 (`rate-limited`).",
            "minimum": 0
          },
          "errorRate": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "(clientErrors + serverErrors + rateLimited) / requests; null without requests."
          },
          "averageDurationMs": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Mean server time in milliseconds; null without requests."
          }
        },
        "required": [
          "requests",
          "clientErrors",
          "serverErrors",
          "rateLimited",
          "errorRate",
          "averageDurationMs"
        ]
      },
      "Approval": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "subjectType": {
            "$ref": "#/components/schemas/ApprovalSubjectType"
          },
          "subjectId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "subjectSummary": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "examples": [
                  "Payment to Acme GmbH"
                ]
              },
              "amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "recipientName": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Recipient (payments, recipients) or counterparty name."
              },
              "sourceBalanceId": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "sourceBalanceName": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "rail": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Rail"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "itemCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Bulk uploads: payments in the batch.",
                "minimum": 0
              },
              "recipientMaskedIdentifier": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Masked account identifier of the recipient the approver binds to (payments: the snapshot taken at submission, which the payment is sent to or refused against; recipients: the current details). Null for other subjects (security audit S-01, D-47)."
              }
            },
            "required": [
              "title"
            ]
          },
          "tier": {
            "type": "integer",
            "minimum": 0
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApprovalStatus"
              }
            ],
            "readOnly": true
          },
          "requiredApprovals": {
            "type": "integer",
            "minimum": 1
          },
          "received": {
            "type": "integer",
            "description": "Approvals received so far (`approved` decisions).",
            "minimum": 0,
            "readOnly": true
          },
          "decisions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "by": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "byName": {
                  "type": "string"
                },
                "decision": {
                  "type": "string",
                  "enum": [
                    "approved",
                    "rejected"
                  ]
                },
                "comment": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "at": {
                  "$ref": "#/components/schemas/Timestamp"
                }
              }
            }
          },
          "requestedBy": {
            "$ref": "#/components/schemas/Uuid"
          },
          "requestedByName": {
            "type": "string"
          },
          "canDecide": {
            "type": "boolean",
            "description": "Whether the caller is an eligible approver (not the requester unless self-approval allowed).",
            "readOnly": true
          },
          "expiresAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "policy": {
            "type": "object",
            "description": "The effective policy tier the request is judged against.",
            "properties": {
              "kind": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/ApprovalPolicyKind"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source": {
                "type": "string",
                "enum": [
                  "snapshot",
                  "policy",
                  "default",
                  "recipient"
                ],
                "description": "`snapshot`: the tier captured when the request opened; `policy`: the current policy; `default`: the built-in single approval; `recipient`: recipient approval mode."
              },
              "tier": {
                "$ref": "#/components/schemas/ApprovalTier"
              },
              "issues": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            },
            "required": [
              "source",
              "tier",
              "issues"
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "subjectType",
          "subjectId",
          "subjectSummary",
          "tier",
          "status",
          "requiredApprovals",
          "received",
          "decisions",
          "requestedBy",
          "canDecide",
          "createdAt"
        ]
      },
      "ApprovalPage": {
        "type": "object",
        "description": "Cursor-paginated list of Approval.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Approval"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "ApprovalPolicyKind": {
        "type": "string",
        "enum": [
          "payment",
          "recipient",
          "funds_request"
        ]
      },
      "ApprovalStatus": {
        "type": "string",
        "enum": [
          "pending",
          "approved",
          "rejected",
          "expired"
        ]
      },
      "ApprovalSubjectType": {
        "type": "string",
        "enum": [
          "payment",
          "recipient",
          "funds_request",
          "primary_owner_transfer",
          "bulk_upload",
          "exchange",
          "approval_policy_change"
        ],
        "description": "`bulk_upload`: one request for a bulk batch (`subjectId` is the bulk upload); `exchange`: reserved for exchanges subject to approval policies (FR-PAY-05). `approval_policy_change`: an approval-policy edit that loosens control (security audit S-07, D-47), decided by an owner or admin other than the requester; `subjectId` is the policy id."
      },
      "ApprovalTier": {
        "type": "object",
        "properties": {
          "minAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "maxAmount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "requiredApprovals": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          },
          "approverRoles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerRole"
            }
          },
          "approverTeamIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          "allowSelfApproval": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "minAmount",
          "requiredApprovals"
        ]
      },
      "Attachment": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "transactionId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "document": {
            "$ref": "#/components/schemas/Document"
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "transactionId",
          "document",
          "createdAt"
        ]
      },
      "AttachmentPage": {
        "type": "object",
        "description": "Cursor-paginated list of Attachment.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Attachment"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "AuditActorType": {
        "type": "string",
        "enum": [
          "user",
          "api_key",
          "system",
          "impersonator"
        ]
      },
      "Balance": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "kind": {
            "type": "string",
            "enum": [
              "customer_balance",
              "customer_sub_balance"
            ],
            "readOnly": true
          },
          "parentBalanceId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AccountStatus"
              }
            ],
            "readOnly": true
          },
          "isFavourite": {
            "type": "boolean"
          },
          "amounts": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BalanceAmounts"
              }
            ],
            "readOnly": true
          },
          "hasAccountDetails": {
            "type": "boolean",
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "required": [
          "id",
          "customerId",
          "currency",
          "name",
          "kind",
          "status",
          "isFavourite",
          "amounts",
          "hasAccountDetails",
          "createdAt"
        ],
        "examples": [
          {
            "id": "0192a6f1-1111-7000-8000-00000000b001",
            "customerId": "0192a6f0-0000-7000-8000-0000000000c1",
            "currency": "GBP",
            "name": "GBP Main",
            "kind": "customer_balance",
            "parentBalanceId": null,
            "status": "active",
            "isFavourite": true,
            "amounts": {
              "available": {
                "amountMinor": "1250050",
                "currency": "GBP"
              },
              "booked": {
                "amountMinor": "1300050",
                "currency": "GBP"
              },
              "pendingOut": {
                "amountMinor": "50000",
                "currency": "GBP"
              },
              "pendingIn": {
                "amountMinor": "0",
                "currency": "GBP"
              },
              "total": {
                "amountMinor": "1300050",
                "currency": "GBP"
              }
            },
            "hasAccountDetails": true,
            "createdAt": "2026-09-23T10:15:30Z"
          }
        ]
      },
      "BalanceAmounts": {
        "type": "object",
        "description": "available = booked − pendingOut; total = booked + pendingIn (Equals \"Total\").",
        "properties": {
          "available": {
            "$ref": "#/components/schemas/Money"
          },
          "booked": {
            "$ref": "#/components/schemas/Money"
          },
          "pendingOut": {
            "$ref": "#/components/schemas/Money"
          },
          "pendingIn": {
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "available",
          "booked",
          "pendingOut",
          "pendingIn",
          "total"
        ]
      },
      "BalancePage": {
        "type": "object",
        "description": "Cursor-paginated list of Balance.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Balance"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "BankingCircleConnectionConfig": {
        "type": "object",
        "properties": {
          "baseUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri",
            "description": "https URL of the provider API (host is checked against the adapter allow-list)"
          },
          "authUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri",
            "description": "https URL of the provider API (host is checked against the adapter allow-list)"
          },
          "companyId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "companyNumber": {
            "type": "string",
            "pattern": "^\\d{9}$"
          },
          "bic": {
            "default": "SXPYDKKKXXX",
            "type": "string",
            "pattern": "^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$"
          },
          "masterAccounts": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string",
                  "enum": [
                    "AED",
                    "AUD",
                    "BGN",
                    "BHD",
                    "BIF",
                    "BRL",
                    "CAD",
                    "CHF",
                    "CLF",
                    "CLP",
                    "CNH",
                    "CNY",
                    "CZK",
                    "DJF",
                    "DKK",
                    "EGP",
                    "EUR",
                    "GBP",
                    "GEL",
                    "GNF",
                    "HKD",
                    "HUF",
                    "IDR",
                    "ILS",
                    "INR",
                    "IQD",
                    "ISK",
                    "JOD",
                    "JPY",
                    "KES",
                    "KMF",
                    "KRW",
                    "KWD",
                    "LYD",
                    "MAD",
                    "MXN",
                    "MYR",
                    "NGN",
                    "NOK",
                    "NZD",
                    "OMR",
                    "PHP",
                    "PLN",
                    "PYG",
                    "QAR",
                    "RON",
                    "RSD",
                    "RWF",
                    "SAR",
                    "SEK",
                    "SGD",
                    "THB",
                    "TND",
                    "TRY",
                    "TWD",
                    "UAH",
                    "UGX",
                    "USD",
                    "UYW",
                    "VND",
                    "VUV",
                    "XAF",
                    "XOF",
                    "XPF",
                    "ZAR"
                  ]
                },
                "accountId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 64
                },
                "iban": {
                  "type": "string",
                  "maxLength": 34
                },
                "accountNumber": {
                  "type": "string",
                  "pattern": "^\\d{6,20}$"
                },
                "validForVirtualAccount": {
                  "default": false,
                  "type": "boolean"
                },
                "protectionType": {
                  "type": "string",
                  "enum": [
                    "None",
                    "ClientMoney",
                    "SafeGuarded"
                  ]
                }
              },
              "required": [
                "currency",
                "accountId"
              ],
              "additionalProperties": false
            }
          },
          "fxSettlementAccounts": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string",
                  "enum": [
                    "AED",
                    "AUD",
                    "BGN",
                    "BHD",
                    "BIF",
                    "BRL",
                    "CAD",
                    "CHF",
                    "CLF",
                    "CLP",
                    "CNH",
                    "CNY",
                    "CZK",
                    "DJF",
                    "DKK",
                    "EGP",
                    "EUR",
                    "GBP",
                    "GEL",
                    "GNF",
                    "HKD",
                    "HUF",
                    "IDR",
                    "ILS",
                    "INR",
                    "IQD",
                    "ISK",
                    "JOD",
                    "JPY",
                    "KES",
                    "KMF",
                    "KRW",
                    "KWD",
                    "LYD",
                    "MAD",
                    "MXN",
                    "MYR",
                    "NGN",
                    "NOK",
                    "NZD",
                    "OMR",
                    "PHP",
                    "PLN",
                    "PYG",
                    "QAR",
                    "RON",
                    "RSD",
                    "RWF",
                    "SAR",
                    "SEK",
                    "SGD",
                    "THB",
                    "TND",
                    "TRY",
                    "TWD",
                    "UAH",
                    "UGX",
                    "USD",
                    "UYW",
                    "VND",
                    "VUV",
                    "XAF",
                    "XOF",
                    "XPF",
                    "ZAR"
                  ]
                },
                "accountId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 64
                }
              },
              "required": [
                "currency",
                "accountId"
              ],
              "additionalProperties": false
            }
          },
          "rails": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "sepa",
                "sepa_instant",
                "swift",
                "faster_payments",
                "chaps",
                "target2"
              ]
            }
          },
          "vibanPolicy": {
            "type": "object",
            "properties": {
              "orderType": {
                "type": "string",
                "enum": [
                  "Reconciliation",
                  "Pobo",
                  "Cobo"
                ]
              },
              "poolSize": {
                "default": 0,
                "type": "integer",
                "minimum": 0,
                "maximum": 100000
              },
              "pool": {
                "maxItems": 20000,
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^\\d{6,20}$"
                }
              },
              "replenishBatch": {
                "default": 50,
                "type": "integer",
                "minimum": 1,
                "maximum": 2500
              },
              "defaultPhysicalAccountId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "countryFormats": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "DK",
                    "LU",
                    "DE",
                    "GB",
                    "SE",
                    "LI",
                    "AU"
                  ]
                }
              }
            },
            "required": [
              "orderType"
            ],
            "additionalProperties": false
          },
          "webhookSubscriptions": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "subscriptionId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 64
                },
                "events": {
                  "maxItems": 20,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  }
                },
                "mtlsEnabled": {
                  "default": false,
                  "type": "boolean"
                }
              },
              "required": [
                "subscriptionId"
              ],
              "additionalProperties": false
            }
          },
          "webhookKeyEncoding": {
            "default": "utf8",
            "type": "string",
            "enum": [
              "utf8",
              "base64"
            ]
          },
          "certificate": {
            "type": "object",
            "properties": {
              "thumbprint": {
                "type": "string",
                "pattern": "^[0-9A-Fa-f]{40}$"
              },
              "expiresAt": {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
              }
            },
            "required": [
              "thumbprint",
              "expiresAt"
            ],
            "additionalProperties": false
          },
          "directDebits": {
            "default": false,
            "type": "boolean"
          },
          "directDebitCreditor": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 70
              },
              "creditorId": {
                "type": "string",
                "pattern": "^[A-Z]{2}\\d{2}[A-Z0-9]{1,31}$"
              },
              "country": {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              "townName": {
                "type": "string",
                "minLength": 1,
                "maxLength": 35
              }
            },
            "required": [
              "name",
              "creditorId",
              "country"
            ],
            "additionalProperties": false
          },
          "heldRates": {
            "default": true,
            "type": "boolean"
          },
          "accountHolderVerification": {
            "default": true,
            "type": "boolean"
          },
          "ahvPoll": {
            "type": "object",
            "properties": {
              "attempts": {
                "default": 5,
                "type": "integer",
                "minimum": 1,
                "maximum": 20
              },
              "intervalMs": {
                "default": 1000,
                "type": "integer",
                "minimum": 0,
                "maximum": 10000
              }
            },
            "additionalProperties": false
          },
          "reconcile": {
            "type": "object",
            "properties": {
              "statementDays": {
                "default": 1,
                "type": "integer",
                "minimum": 1,
                "maximum": 31
              },
              "pageSize": {
                "default": 500,
                "type": "integer",
                "minimum": 10,
                "maximum": 5000
              },
              "source": {
                "default": "reconciliation_report",
                "type": "string",
                "enum": [
                  "reconciliation_report",
                  "statement"
                ]
              }
            },
            "additionalProperties": false
          },
          "transactionsWindowDays": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 180
          },
          "truncate": {
            "default": false,
            "type": "boolean"
          },
          "inboundIpAllowList": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "cidrv4",
                  "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$"
                },
                {
                  "type": "string",
                  "format": "cidrv6",
                  "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$"
                }
              ]
            }
          }
        },
        "required": [
          "baseUrl",
          "authUrl",
          "companyId",
          "companyNumber",
          "masterAccounts",
          "rails"
        ],
        "additionalProperties": false,
        "description": "Banking Circle connection configuration (non-secret; from the adapter schema in `@wirebloom/providers`)."
      },
      "BatchCsvConnectionConfig": {
        "type": "object",
        "properties": {
          "bankName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 70
          },
          "initiatingPartyName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 70
          },
          "accounts": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string",
                  "enum": [
                    "AED",
                    "AUD",
                    "BGN",
                    "BHD",
                    "BIF",
                    "BRL",
                    "CAD",
                    "CHF",
                    "CLF",
                    "CLP",
                    "CNH",
                    "CNY",
                    "CZK",
                    "DJF",
                    "DKK",
                    "EGP",
                    "EUR",
                    "GBP",
                    "GEL",
                    "GNF",
                    "HKD",
                    "HUF",
                    "IDR",
                    "ILS",
                    "INR",
                    "IQD",
                    "ISK",
                    "JOD",
                    "JPY",
                    "KES",
                    "KMF",
                    "KRW",
                    "KWD",
                    "LYD",
                    "MAD",
                    "MXN",
                    "MYR",
                    "NGN",
                    "NOK",
                    "NZD",
                    "OMR",
                    "PHP",
                    "PLN",
                    "PYG",
                    "QAR",
                    "RON",
                    "RSD",
                    "RWF",
                    "SAR",
                    "SEK",
                    "SGD",
                    "THB",
                    "TND",
                    "TRY",
                    "TWD",
                    "UAH",
                    "UGX",
                    "USD",
                    "UYW",
                    "VND",
                    "VUV",
                    "XAF",
                    "XOF",
                    "XPF",
                    "ZAR"
                  ]
                },
                "iban": {
                  "type": "string",
                  "pattern": "^[A-Z]{2}\\d{2}[A-Z0-9]{11,30}$"
                },
                "bic": {
                  "type": "string",
                  "pattern": "^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$"
                },
                "accountHolderName": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 70
                }
              },
              "required": [
                "currency",
                "iban",
                "accountHolderName"
              ],
              "additionalProperties": false
            }
          },
          "rails": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "sepa",
                "sepa_instant",
                "swift",
                "faster_payments",
                "chaps",
                "bacs",
                "local"
              ]
            }
          },
          "defaultFormat": {
            "default": "csv",
            "type": "string",
            "enum": [
              "csv",
              "pain001"
            ]
          },
          "fx": {
            "type": "object",
            "properties": {
              "rates": {
                "minItems": 1,
                "maxItems": 200,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "sell": {
                      "type": "string",
                      "enum": [
                        "AED",
                        "AUD",
                        "BGN",
                        "BHD",
                        "BIF",
                        "BRL",
                        "CAD",
                        "CHF",
                        "CLF",
                        "CLP",
                        "CNH",
                        "CNY",
                        "CZK",
                        "DJF",
                        "DKK",
                        "EGP",
                        "EUR",
                        "GBP",
                        "GEL",
                        "GNF",
                        "HKD",
                        "HUF",
                        "IDR",
                        "ILS",
                        "INR",
                        "IQD",
                        "ISK",
                        "JOD",
                        "JPY",
                        "KES",
                        "KMF",
                        "KRW",
                        "KWD",
                        "LYD",
                        "MAD",
                        "MXN",
                        "MYR",
                        "NGN",
                        "NOK",
                        "NZD",
                        "OMR",
                        "PHP",
                        "PLN",
                        "PYG",
                        "QAR",
                        "RON",
                        "RSD",
                        "RWF",
                        "SAR",
                        "SEK",
                        "SGD",
                        "THB",
                        "TND",
                        "TRY",
                        "TWD",
                        "UAH",
                        "UGX",
                        "USD",
                        "UYW",
                        "VND",
                        "VUV",
                        "XAF",
                        "XOF",
                        "XPF",
                        "ZAR"
                      ]
                    },
                    "buy": {
                      "type": "string",
                      "enum": [
                        "AED",
                        "AUD",
                        "BGN",
                        "BHD",
                        "BIF",
                        "BRL",
                        "CAD",
                        "CHF",
                        "CLF",
                        "CLP",
                        "CNH",
                        "CNY",
                        "CZK",
                        "DJF",
                        "DKK",
                        "EGP",
                        "EUR",
                        "GBP",
                        "GEL",
                        "GNF",
                        "HKD",
                        "HUF",
                        "IDR",
                        "ILS",
                        "INR",
                        "IQD",
                        "ISK",
                        "JOD",
                        "JPY",
                        "KES",
                        "KMF",
                        "KRW",
                        "KWD",
                        "LYD",
                        "MAD",
                        "MXN",
                        "MYR",
                        "NGN",
                        "NOK",
                        "NZD",
                        "OMR",
                        "PHP",
                        "PLN",
                        "PYG",
                        "QAR",
                        "RON",
                        "RSD",
                        "RWF",
                        "SAR",
                        "SEK",
                        "SGD",
                        "THB",
                        "TND",
                        "TRY",
                        "TWD",
                        "UAH",
                        "UGX",
                        "USD",
                        "UYW",
                        "VND",
                        "VUV",
                        "XAF",
                        "XOF",
                        "XPF",
                        "ZAR"
                      ]
                    },
                    "rate": {
                      "type": "string",
                      "pattern": "^\\d{1,10}(\\.\\d{1,10})?$"
                    }
                  },
                  "required": [
                    "sell",
                    "buy",
                    "rate"
                  ],
                  "additionalProperties": false
                }
              },
              "quoteTtlSeconds": {
                "default": 300,
                "type": "integer",
                "minimum": 5,
                "maximum": 86400
              }
            },
            "required": [
              "rates"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "bankName",
          "initiatingPartyName",
          "accounts",
          "rails"
        ],
        "additionalProperties": false,
        "description": "Bank file (operator-run) connection configuration (non-secret; from the adapter schema in `@wirebloom/providers`)."
      },
      "BulkPayment": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "documentId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "sourceBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BulkUploadStatus"
              }
            ],
            "readOnly": true
          },
          "rowsTotal": {
            "type": "integer"
          },
          "rowsOk": {
            "type": "integer"
          },
          "rowsFailed": {
            "type": "integer"
          },
          "total": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "resultsDocumentId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Per-row results file (CSV document, `GET /documents/{documentId}/download`) written after validation and after submission; null until produced.",
            "format": "uuid",
            "readOnly": true
          },
          "createdBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "customerId",
          "documentId",
          "sourceBalanceId",
          "status",
          "rowsTotal",
          "rowsOk",
          "rowsFailed",
          "createdAt"
        ]
      },
      "BulkPaymentCreate": {
        "type": "object",
        "description": "Upload the CSV first via `POST /documents` (`kind=bulk_payments`). Validation is asynchronous.",
        "properties": {
          "documentId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "sourceBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "template": {
            "type": "string",
            "enum": [
              "wirebloom_csv_v1"
            ],
            "default": "wirebloom_csv_v1"
          }
        },
        "required": [
          "documentId",
          "sourceBalanceId"
        ],
        "additionalProperties": false
      },
      "BulkPaymentPage": {
        "type": "object",
        "description": "Cursor-paginated list of BulkPayment.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkPayment"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "BulkPaymentRow": {
        "type": "object",
        "properties": {
          "row": {
            "type": "integer",
            "minimum": 1
          },
          "status": {
            "type": "string",
            "enum": [
              "valid",
              "invalid",
              "submitted",
              "failed"
            ]
          },
          "paymentId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldError"
            }
          },
          "recipientName": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "row",
          "status",
          "errors"
        ]
      },
      "BulkPaymentRowPage": {
        "type": "object",
        "description": "Cursor-paginated list of BulkPaymentRow.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkPaymentRow"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "BulkPaymentSubmitAccepted": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Job"
          },
          {
            "type": "object",
            "properties": {
              "bulkPayment": {
                "$ref": "#/components/schemas/BulkPayment"
              }
            },
            "required": [
              "bulkPayment"
            ]
          }
        ],
        "description": "`202` of submit: the job that creates the payments in the background (`kind` `bulk_validation`, poll `GET /jobs/{jobId}` for `progress`) and the batch as it stands (`status` `submitting`; poll `GET /bulk-payments/{bulkPaymentId}` for the final `submitted` / `partially_submitted` and the row results)."
      },
      "BulkUploadStatus": {
        "type": "string",
        "enum": [
          "uploaded",
          "validating",
          "validated",
          "validation_failed",
          "submitting",
          "submitted",
          "partially_submitted",
          "cancelled"
        ],
        "description": "ASSUMPTION: untyped in DATABASE.md."
      },
      "CancelRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          }
        },
        "additionalProperties": false
      },
      "Channel": {
        "type": "string",
        "enum": [
          "web",
          "mobile",
          "api",
          "staff"
        ]
      },
      "ChargeBearer": {
        "type": "string",
        "enum": [
          "our",
          "sha",
          "ben"
        ]
      },
      "Collection": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "mandateId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "dueDate": {
            "$ref": "#/components/schemas/Date"
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CollectionStatus"
              }
            ],
            "readOnly": true
          },
          "providerRef": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "transactionId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "failureReason": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "sequenceType": {
            "type": "string",
            "enum": [
              "FRST",
              "RCUR",
              "OOFF",
              "FNAL"
            ],
            "readOnly": true
          },
          "submitOn": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "collectedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "returnReasonCode": {
            "type": [
              "string",
              "null"
            ],
            "description": "R-transaction reason code (SEPA / Bacs ARUDD).",
            "readOnly": true
          },
          "returnedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "scheduledPaymentId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "mandateId",
          "amount",
          "dueDate",
          "status",
          "createdAt"
        ]
      },
      "CollectionCreate": {
        "type": "object",
        "properties": {
          "mandateId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "dueDate": {
            "$ref": "#/components/schemas/Date"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 35
          }
        },
        "required": [
          "mandateId",
          "amount",
          "dueDate"
        ],
        "additionalProperties": false
      },
      "CollectionPage": {
        "type": "object",
        "description": "Cursor-paginated list of Collection.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Collection"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "CollectionScheduleCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 35
          },
          "schedule": {
            "type": "object",
            "properties": {
              "rrule": {
                "type": "string"
              },
              "startDate": {
                "$ref": "#/components/schemas/Date"
              },
              "endDate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "timezone": {
                "type": "string"
              }
            },
            "required": [
              "rrule",
              "startDate"
            ]
          }
        },
        "required": [
          "amount",
          "schedule"
        ],
        "additionalProperties": false
      },
      "CollectionScheduleTemplate": {
        "type": "object",
        "description": "Direct debit collection schedule template (`kind: collection`, created with `POST /mandates/{mandateId}/schedules`).",
        "properties": {
          "mandateId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "mandateId",
          "amount"
        ]
      },
      "CollectionStatus": {
        "type": "string",
        "enum": [
          "scheduled",
          "submitted",
          "collected",
          "failed",
          "returned",
          "cancelled"
        ],
        "description": "ASSUMPTION: untyped in DATABASE.md."
      },
      "ConnectionLifecycle": {
        "type": "string",
        "enum": [
          "draft",
          "configured",
          "testing",
          "active",
          "draining",
          "retired"
        ],
        "description": "Banking connection lifecycle (D-32, P5-T07): `draft` (created) → `configured` (a dry run validated the configuration and credentials) → `testing` (the full test passed) → `active` (activated through the checklist; carries new work) → `draining` (no new work; in-flight items, reconciliation and late credits continue) → `retired`. At most one `active` primary, one `active` fallback and one `draining` connection per (operator, environment). Health is `healthy` / `lastHealth`, not a state."
      },
      "ConnectionRole": {
        "type": "string",
        "enum": [
          "primary",
          "fallback"
        ],
        "description": "`primary`: the operator's banking integration in the environment; `fallback`: the batch rail, carrying only `fallbackCurrencies` the active partner does not offer, never the same currency (Q-53)."
      },
      "ContractModel": {
        "type": "string",
        "enum": [
          "master",
          "direct"
        ],
        "description": "Banking Circle contracting model (D-39): `master` = WireBloom's contract with per-operator sub-allocation of master accounts and VIBAN pools; `direct` = the operator's own M2M user, certificates and accounts."
      },
      "CountryCode": {
        "type": "string",
        "description": "ISO 3166-1 alpha-2 country code.",
        "pattern": "^[A-Z]{2}$",
        "examples": [
          "GB"
        ]
      },
      "Currency": {
        "type": "object",
        "properties": {
          "code": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "name": {
            "type": "string"
          },
          "exponent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4
          },
          "offered": {
            "type": "boolean"
          },
          "enabled": {
            "type": "boolean",
            "description": "Enabled for the tenant in `X-Tenant-Id` (customers only)."
          },
          "rails": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Rail"
            }
          },
          "fxAvailable": {
            "type": "boolean"
          }
        },
        "required": [
          "code",
          "name",
          "exponent",
          "offered",
          "rails"
        ]
      },
      "CurrencyCode": {
        "type": "string",
        "description": "ISO 4217 alphabetic currency code.",
        "pattern": "^[A-Z]{3}$",
        "examples": [
          "GBP"
        ]
      },
      "CurrencySetting": {
        "type": "object",
        "properties": {
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "name": {
            "type": "string",
            "examples": [
              "British Pound"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "offered": {
            "type": "boolean",
            "description": "Offered by the operator."
          },
          "cardSpendable": {
            "type": "boolean"
          },
          "rails": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Rail"
            }
          }
        },
        "required": [
          "currency",
          "name",
          "enabled",
          "offered"
        ]
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "operatorId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "number": {
            "type": "string",
            "description": "8-digit display id, unique per operator.",
            "pattern": "^[0-9]{8}$",
            "readOnly": true
          },
          "legalName": {
            "type": "string",
            "maxLength": 200
          },
          "tradingName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "identityType": {
            "$ref": "#/components/schemas/IdentityType"
          },
          "registrationNumber": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          },
          "incorporationCountry": {
            "$ref": "#/components/schemas/CountryCode"
          },
          "incorporationDate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CustomerStatus"
              }
            ],
            "readOnly": true
          },
          "risk": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RiskRating"
              },
              {
                "type": "null"
              }
            ]
          },
          "approvedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "closedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "customerType": {
            "$ref": "#/components/schemas/CustomerType"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "accessStatus": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AccessStatus"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "operatorId",
          "number",
          "legalName",
          "identityType",
          "incorporationCountry",
          "status",
          "createdAt"
        ],
        "examples": [
          {
            "id": "0192a6f0-0000-7000-8000-0000000000c1",
            "operatorId": "0192a6f0-0000-7000-8000-00000000000a",
            "number": "23704400",
            "legalName": "WireBloom Ltd",
            "tradingName": "WireBloom",
            "identityType": "corporate",
            "registrationNumber": "12345678",
            "incorporationCountry": "GB",
            "incorporationDate": "2019-04-01",
            "status": "approved",
            "risk": "low",
            "createdAt": "2026-09-23T10:15:30Z"
          }
        ]
      },
      "CustomerCreate": {
        "type": "object",
        "properties": {
          "legalName": {
            "type": "string",
            "maxLength": 200
          },
          "tradingName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "identityType": {
            "$ref": "#/components/schemas/IdentityType"
          },
          "registrationNumber": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          },
          "incorporationCountry": {
            "$ref": "#/components/schemas/CountryCode"
          },
          "primaryOwner": {
            "type": "object",
            "properties": {
              "email": {
                "$ref": "#/components/schemas/Email"
              },
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              }
            },
            "required": [
              "email",
              "firstName",
              "lastName"
            ]
          },
          "pricingTemplateId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "customerType": {
            "$ref": "#/components/schemas/CustomerType"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "required": [
          "legalName",
          "incorporationCountry"
        ],
        "additionalProperties": false,
        "description": "Send `customerType` (P10-T03); `identityType` is derived (`corporate` for businesses, `individual` otherwise) and may be omitted; when both are sent they must agree (`422`). For sole traders and individuals `legalName` is the person's full name and `incorporationCountry` the country of residence; an individual has no registration number. `primaryOwner` is optional for console sessions: the customer is then created as a `draft` without an invitation, and staff invite the owner later (`POST /ops/customers/{customerId}/owner-invitation`). API keys must still send it (`422` with field `/primaryOwner`)."
      },
      "CustomerPage": {
        "type": "object",
        "description": "Cursor-paginated list of Customer.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Customer"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "CustomerRole": {
        "type": "string",
        "enum": [
          "cust_owner",
          "cust_admin",
          "cust_member",
          "cust_viewer"
        ],
        "description": "Assignable customer roles (`cust_primary_owner` is only assigned via primary-owner transfer)."
      },
      "CustomerStatus": {
        "type": "string",
        "enum": [
          "draft",
          "submitted",
          "in_review",
          "info_requested",
          "approved",
          "declined",
          "on_hold",
          "inactive",
          "closed"
        ]
      },
      "CustomerType": {
        "type": "string",
        "enum": [
          "business",
          "sole_trader",
          "individual"
        ],
        "description": "P10-T03 (FR-ONB-07): `business` is verified with KYB (company applicant, persons, company documents); `sole_trader` and `individual` are natural persons verified with KYC (one individual applicant, identity and proof-of-address documents). Available to every operator (owner decision 2026-09-24)."
      },
      "Date": {
        "type": "string",
        "description": "ISO 8601 calendar date.",
        "format": "date",
        "examples": [
          "2026-09-30"
        ]
      },
      "DepositBalance": {
        "type": "object",
        "description": "Deposits held against open forward contracts (Equals \"View deposit balance\").",
        "properties": {
          "balances": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "currency": {
                  "$ref": "#/components/schemas/CurrencyCode"
                },
                "held": {
                  "$ref": "#/components/schemas/Money"
                },
                "contracts": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "required": [
                "currency",
                "held",
                "contracts"
              ]
            }
          }
        },
        "required": [
          "balances"
        ]
      },
      "DeveloperRegistrationMode": {
        "type": "string",
        "enum": [
          "invite",
          "open"
        ],
        "description": "`invite`: operator staff invite developers (default); `open`: self-registration from the developer portal."
      },
      "DeveloperRegistrationStatus": {
        "type": "string",
        "enum": [
          "pending",
          "provisioned",
          "expired",
          "revoked"
        ]
      },
      "DeveloperWorkspace": {
        "type": "object",
        "properties": {
          "registrationId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "customerId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "mode": {
            "$ref": "#/components/schemas/DeveloperRegistrationMode"
          },
          "status": {
            "$ref": "#/components/schemas/DeveloperRegistrationStatus"
          },
          "provisionedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "lastActiveAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Idle expiry (the programme's `idleExpiryDays` after the last activity).",
            "format": "date-time"
          },
          "connection": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "provider": {
                "type": "string"
              },
              "environment": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "provider",
              "environment"
            ]
          },
          "activeTestKeys": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "registrationId",
          "customerId",
          "mode",
          "status",
          "provisionedAt",
          "lastActiveAt",
          "expiresAt",
          "connection",
          "activeTestKeys"
        ]
      },
      "Document": {
        "type": "object",
        "description": "Uploaded or generated document. Downloads are available only when `status=clean` (`scanStatus` is the coarse scan view of `status`).",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "kyb_company",
              "kyb_person_id",
              "kyb_proof_of_address",
              "kyb_ownership",
              "kyb_other",
              "attachment",
              "bulk_payments",
              "statement",
              "confirmation",
              "export",
              "other"
            ]
          },
          "fileName": {
            "type": "string",
            "maxLength": 255
          },
          "contentType": {
            "type": "string",
            "enum": [
              "application/pdf",
              "image/png",
              "image/jpeg",
              "text/csv",
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            ]
          },
          "size": {
            "type": "integer",
            "description": "Bytes.",
            "minimum": 1,
            "maximum": 20971520
          },
          "sha256": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$",
            "readOnly": true
          },
          "scanStatus": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DocumentScanStatus"
              }
            ],
            "readOnly": true
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DocumentStatus"
              }
            ],
            "readOnly": true
          },
          "uploadedBy": {
            "type": [
              "string",
              "null"
            ],
            "description": "Uploading user; null for platform-generated documents.",
            "format": "uuid",
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "kind",
          "fileName",
          "contentType",
          "size",
          "scanStatus",
          "status",
          "createdAt"
        ]
      },
      "DocumentScanStatus": {
        "type": "string",
        "enum": [
          "pending",
          "clean",
          "infected"
        ]
      },
      "DocumentStatus": {
        "type": "string",
        "enum": [
          "pending_upload",
          "scanning",
          "clean",
          "infected"
        ],
        "description": "Upload lifecycle: `pending_upload` (intent created) → `scanning` (upload completed) → `clean` | `infected` (quarantined). Generated documents are `clean`."
      },
      "DownloadLink": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Pre-signed URL (S3), valid for `expiresAt`.",
            "format": "uri"
          },
          "expiresAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "contentType": {
            "type": "string",
            "examples": [
              "application/pdf"
            ]
          },
          "fileName": {
            "type": "string",
            "examples": [
              "statement-2026-08-GBP.pdf"
            ]
          }
        },
        "required": [
          "url",
          "expiresAt",
          "contentType"
        ]
      },
      "Drawdown": {
        "type": "object",
        "description": "Use part of the remaining forward balance (settle to buy balance or fund a payment).",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "paymentId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "amount"
        ],
        "additionalProperties": false
      },
      "Email": {
        "type": "string",
        "description": "Email address.",
        "format": "email",
        "maxLength": 254,
        "examples": [
          "alex@wirebloom.com"
        ]
      },
      "Exchange": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "kind": {
            "$ref": "#/components/schemas/ExchangeKind"
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ExchangeStatus"
              }
            ],
            "readOnly": true
          },
          "sellBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "buyBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "sellAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "buyAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "rate": {
            "$ref": "#/components/schemas/Rate"
          },
          "fixedSide": {
            "$ref": "#/components/schemas/FixedSide"
          },
          "quoteId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "fee": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "settlementDate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "deposit": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "remaining": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "orderId": {
            "type": "string",
            "description": "Human order id shown on confirmations.",
            "examples": [
              "E3B0LTLU2UXT"
            ],
            "readOnly": true
          },
          "providerRef": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "createdBy": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "completedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "purpose": {
            "type": "string",
            "enum": [
              "exchange",
              "add_money",
              "payment"
            ],
            "description": "What the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.",
            "readOnly": true
          },
          "statusReason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the exchange failed or was cancelled.",
            "readOnly": true
          },
          "marginCall": {
            "type": [
              "object",
              "null"
            ],
            "description": "Open margin call on a forward: deposit top-up required (`POST /forward-contracts/{exchangeId}/deposit`).",
            "properties": {
              "at": {
                "$ref": "#/components/schemas/Timestamp"
              },
              "amount": {
                "$ref": "#/components/schemas/Money"
              }
            },
            "required": [
              "at",
              "amount"
            ],
            "readOnly": true
          },
          "drawdownCount": {
            "type": "integer",
            "description": "Drawdowns requested on a forward or held-rate contract.",
            "minimum": 0,
            "readOnly": true
          }
        },
        "required": [
          "id",
          "customerId",
          "kind",
          "status",
          "sellBalanceId",
          "buyBalanceId",
          "sellAmount",
          "buyAmount",
          "rate",
          "fixedSide",
          "quoteId",
          "orderId",
          "createdAt"
        ]
      },
      "ExchangeCreate": {
        "type": "object",
        "description": "Execute a live quote. Expired quote → `409` `quote-expired`.",
        "properties": {
          "quoteId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "sellBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "buyBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          }
        },
        "required": [
          "quoteId",
          "sellBalanceId",
          "buyBalanceId"
        ],
        "additionalProperties": false,
        "examples": [
          {
            "quoteId": "0192a6f1-4444-7000-8000-00000000d001",
            "sellBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
            "buyBalanceId": "0192a6f1-1111-7000-8000-00000000b003"
          }
        ]
      },
      "ExchangeKind": {
        "type": "string",
        "enum": [
          "spot",
          "forward",
          "held_rate"
        ]
      },
      "ExchangePage": {
        "type": "object",
        "description": "Cursor-paginated list of Exchange.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Exchange"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "ExchangeStatus": {
        "type": "string",
        "enum": [
          "pending_approval",
          "awaiting_deposit",
          "open",
          "processing",
          "completed",
          "failed",
          "cancelled"
        ],
        "description": "ASSUMPTION: DATABASE.md `exchanges.status` is untyped. `open` = forward/held-rate contract with remaining balance."
      },
      "ExportFormat": {
        "type": "string",
        "enum": [
          "csv",
          "pdf",
          "xlsx"
        ]
      },
      "ExportRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "statement",
              "transaction_activity"
            ]
          },
          "format": {
            "$ref": "#/components/schemas/ExportFormat"
          },
          "balanceIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          "from": {
            "$ref": "#/components/schemas/Date"
          },
          "to": {
            "$ref": "#/components/schemas/Date"
          },
          "filter": {
            "$ref": "#/components/schemas/TransactionExportFilter"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "kind",
          "format",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "FeeCode": {
        "type": "string",
        "enum": [
          "setup",
          "monthly",
          "incoming_local",
          "incoming_xborder",
          "outgoing_local",
          "outgoing_xborder",
          "fx",
          "urgent",
          "correspondent",
          "swift_confirmation",
          "recall",
          "custom"
        ],
        "description": "Built-in fee codes; operator-defined codes are sent as `custom` with `customCode`."
      },
      "FeeLine": {
        "type": "object",
        "properties": {
          "code": {
            "$ref": "#/components/schemas/FeeCode"
          },
          "label": {
            "type": "string",
            "examples": [
              "Outgoing SEPA fee"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "code",
          "label",
          "amount"
        ]
      },
      "FieldError": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "description": "JSON Pointer (RFC 6901) to the offending field in the request body, or `query.<name>` / `header.<name>` for parameters.",
            "examples": [
              "/amount/amountMinor"
            ]
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code.",
            "examples": [
              "too_small"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable message (English; not for programmatic use).",
            "examples": [
              "Amount must be greater than zero."
            ]
          }
        },
        "required": [
          "field",
          "code",
          "message"
        ]
      },
      "FixedSide": {
        "type": "string",
        "enum": [
          "sell",
          "buy"
        ],
        "description": "Which side of the exchange amount is fixed."
      },
      "ForwardContractCreate": {
        "type": "object",
        "description": "Book a forward or held-rate contract from a `forward`/`held_rate` quote. Deposit is taken from `depositBalanceId` when required.",
        "properties": {
          "quoteId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "sellBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "buyBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "depositBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "quoteId",
          "sellBalanceId",
          "buyBalanceId"
        ],
        "additionalProperties": false
      },
      "ForwardDepositTopUp": {
        "type": "object",
        "description": "Deposit top-up for an open forward (margin call), in the contract's sell currency; taken from `fromBalanceId` (default: the sell balance). Clears the margin call when it covers it.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "fromBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "amount"
        ],
        "additionalProperties": false
      },
      "FundsRequest": {
        "type": "object",
        "description": "Equals \"Requests\": a member asks balance holders for funds (e.g. to a sub-balance or card). Fulfilment is an internal transfer (`transferId`) into `balanceId` from the approver's chosen source.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "reason": {
            "type": "string",
            "maxLength": 500
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FundsRequestStatus"
              }
            ],
            "readOnly": true
          },
          "approvalId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "requestedBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "decidedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "fromBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "transferId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "decisionReason": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "expiresAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "customerId",
          "balanceId",
          "amount",
          "reason",
          "status",
          "requestedBy",
          "createdAt"
        ]
      },
      "FundsRequestCreate": {
        "type": "object",
        "properties": {
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "reason": {
            "type": "string",
            "minLength": 3,
            "maxLength": 500
          },
          "fromBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "balanceId",
          "amount",
          "reason"
        ],
        "additionalProperties": false
      },
      "FundsRequestPage": {
        "type": "object",
        "description": "Cursor-paginated list of FundsRequest.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FundsRequest"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "FundsRequestStatus": {
        "type": "string",
        "enum": [
          "pending",
          "approved",
          "rejected",
          "cancelled",
          "fulfilled",
          "expired"
        ],
        "description": "DATABASE.md `tenant.funds_request_status`; `expired` when the approval window lapses."
      },
      "Hold": {
        "type": "object",
        "description": "Pending outgoing amount reserved against a balance (`ledger.holds`).",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "status": {
            "$ref": "#/components/schemas/HoldStatus"
          },
          "subject": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "payment",
                  "exchange",
                  "add_money",
                  "card_transaction",
                  "collection",
                  "billing_item",
                  "payment_review"
                ]
              },
              "id": {
                "$ref": "#/components/schemas/Uuid"
              }
            },
            "required": [
              "type",
              "id"
            ],
            "description": "What the hold reserves funds for. `payment_review`: funds reserved while a payment is processed; its `id` is the hold's own id (no further detail is available to customers or integrators)."
          },
          "description": {
            "type": "string"
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "releasedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "balanceId",
          "amount",
          "status",
          "subject",
          "description",
          "createdAt"
        ]
      },
      "HoldPage": {
        "type": "object",
        "description": "Cursor-paginated list of Hold.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Hold"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "HoldStatus": {
        "type": "string",
        "enum": [
          "active",
          "released",
          "captured"
        ]
      },
      "IdentityType": {
        "type": "string",
        "enum": [
          "corporate",
          "individual"
        ]
      },
      "IntegratedFinanceConnectionConfig": {
        "type": "object",
        "properties": {
          "baseUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri",
            "description": "https URL of the provider API (host is checked against the adapter allow-list)"
          },
          "authUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri",
            "description": "https URL of the provider API (host is checked against the adapter allow-list)"
          },
          "instanceId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9-]{1,100}$"
          },
          "connectPolicy": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "implicit",
                  "explicit"
                ]
              },
              "providerCode": {
                "type": "string",
                "pattern": "^[a-z0-9-]{1,100}$"
              }
            },
            "required": [
              "mode"
            ],
            "additionalProperties": false
          },
          "serviceProvider": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,100}$"
          },
          "pricingPolicy": {
            "default": "implicit",
            "type": "string",
            "enum": [
              "implicit",
              "explicit"
            ]
          },
          "explicitPricing": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "fixed"
                  },
                  "amount": {
                    "type": "string",
                    "pattern": "^\\d{1,12}(\\.\\d{1,6})?$"
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "AED",
                      "AUD",
                      "BGN",
                      "BHD",
                      "BIF",
                      "BRL",
                      "CAD",
                      "CHF",
                      "CLF",
                      "CLP",
                      "CNH",
                      "CNY",
                      "CZK",
                      "DJF",
                      "DKK",
                      "EGP",
                      "EUR",
                      "GBP",
                      "GEL",
                      "GNF",
                      "HKD",
                      "HUF",
                      "IDR",
                      "ILS",
                      "INR",
                      "IQD",
                      "ISK",
                      "JOD",
                      "JPY",
                      "KES",
                      "KMF",
                      "KRW",
                      "KWD",
                      "LYD",
                      "MAD",
                      "MXN",
                      "MYR",
                      "NGN",
                      "NOK",
                      "NZD",
                      "OMR",
                      "PHP",
                      "PLN",
                      "PYG",
                      "QAR",
                      "RON",
                      "RSD",
                      "RWF",
                      "SAR",
                      "SEK",
                      "SGD",
                      "THB",
                      "TND",
                      "TRY",
                      "TWD",
                      "UAH",
                      "UGX",
                      "USD",
                      "UYW",
                      "VND",
                      "VUV",
                      "XAF",
                      "XOF",
                      "XPF",
                      "ZAR"
                    ]
                  }
                },
                "required": [
                  "type",
                  "amount",
                  "currency"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "ratio"
                  },
                  "ratio": {
                    "type": "string",
                    "pattern": "^0?\\.\\d{1,8}$"
                  },
                  "boundaryCurrency": {
                    "type": "string",
                    "enum": [
                      "AED",
                      "AUD",
                      "BGN",
                      "BHD",
                      "BIF",
                      "BRL",
                      "CAD",
                      "CHF",
                      "CLF",
                      "CLP",
                      "CNH",
                      "CNY",
                      "CZK",
                      "DJF",
                      "DKK",
                      "EGP",
                      "EUR",
                      "GBP",
                      "GEL",
                      "GNF",
                      "HKD",
                      "HUF",
                      "IDR",
                      "ILS",
                      "INR",
                      "IQD",
                      "ISK",
                      "JOD",
                      "JPY",
                      "KES",
                      "KMF",
                      "KRW",
                      "KWD",
                      "LYD",
                      "MAD",
                      "MXN",
                      "MYR",
                      "NGN",
                      "NOK",
                      "NZD",
                      "OMR",
                      "PHP",
                      "PLN",
                      "PYG",
                      "QAR",
                      "RON",
                      "RSD",
                      "RWF",
                      "SAR",
                      "SEK",
                      "SGD",
                      "THB",
                      "TND",
                      "TRY",
                      "TWD",
                      "UAH",
                      "UGX",
                      "USD",
                      "UYW",
                      "VND",
                      "VUV",
                      "XAF",
                      "XOF",
                      "XPF",
                      "ZAR"
                    ]
                  },
                  "minimumAmount": {
                    "type": "string",
                    "pattern": "^\\d{1,12}(\\.\\d{1,6})?$"
                  },
                  "maximumAmount": {
                    "type": "string",
                    "pattern": "^\\d{1,12}(\\.\\d{1,6})?$"
                  }
                },
                "required": [
                  "type",
                  "ratio",
                  "boundaryCurrency"
                ],
                "additionalProperties": false
              }
            ]
          },
          "complianceMode": {
            "default": "if_managed",
            "type": "string",
            "enum": [
              "if_managed",
              "external"
            ]
          },
          "organisationAccounts": {
            "type": "object",
            "properties": {
              "clientMoney": {
                "type": "string",
                "pattern": "^[A-Za-z0-9-]{1,100}$"
              },
              "feeCollection": {
                "type": "string",
                "pattern": "^[A-Za-z0-9-]{1,100}$"
              },
              "suspense": {
                "type": "string",
                "pattern": "^[A-Za-z0-9-]{1,100}$"
              }
            },
            "required": [
              "clientMoney",
              "feeCollection",
              "suspense"
            ],
            "additionalProperties": false
          },
          "genericTransactionTypes": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "schemes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "sepa",
                "sepa-instant",
                "swift",
                "faster-payments",
                "chaps",
                "bacs",
                "sepa-target-2",
                "ach",
                "wire",
                "eft"
              ]
            }
          },
          "currencies": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "AED",
                "AUD",
                "BGN",
                "BHD",
                "BIF",
                "BRL",
                "CAD",
                "CHF",
                "CLF",
                "CLP",
                "CNH",
                "CNY",
                "CZK",
                "DJF",
                "DKK",
                "EGP",
                "EUR",
                "GBP",
                "GEL",
                "GNF",
                "HKD",
                "HUF",
                "IDR",
                "ILS",
                "INR",
                "IQD",
                "ISK",
                "JOD",
                "JPY",
                "KES",
                "KMF",
                "KRW",
                "KWD",
                "LYD",
                "MAD",
                "MXN",
                "MYR",
                "NGN",
                "NOK",
                "NZD",
                "OMR",
                "PHP",
                "PLN",
                "PYG",
                "QAR",
                "RON",
                "RSD",
                "RWF",
                "SAR",
                "SEK",
                "SGD",
                "THB",
                "TND",
                "TRY",
                "TWD",
                "UAH",
                "UGX",
                "USD",
                "UYW",
                "VND",
                "VUV",
                "XAF",
                "XOF",
                "XPF",
                "ZAR"
              ]
            }
          },
          "accountModel": {
            "default": "real",
            "type": "string",
            "enum": [
              "virtual",
              "real",
              "shared_pool"
            ]
          },
          "multiCurrencyBankAccounts": {
            "default": false,
            "type": "boolean"
          },
          "transactionAccounts": {
            "default": "create",
            "type": "string",
            "enum": [
              "auto",
              "create"
            ]
          },
          "sourceAccountType": {
            "default": "transaction-account",
            "type": "string",
            "enum": [
              "transaction-account",
              "client-account"
            ]
          },
          "resolveTransferDate": {
            "default": true,
            "type": "boolean"
          },
          "chargeBearerSchemeAttribute": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "verificationClientId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9-]{1,100}$"
          },
          "cardsEnabled": {
            "default": false,
            "type": "boolean"
          },
          "webhookPublicKeys": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "version": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 20
                },
                "publicKeyPem": {
                  "type": "string",
                  "maxLength": 2000,
                  "format": "includes",
                  "pattern": "BEGIN PUBLIC KEY"
                }
              },
              "required": [
                "version",
                "publicKeyPem"
              ],
              "additionalProperties": false
            }
          },
          "webhookToleranceSeconds": {
            "default": 600,
            "type": "integer",
            "minimum": 60,
            "maximum": 3600
          },
          "statementLookbackDays": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 730
          },
          "reconcileWindowHours": {
            "default": 48,
            "type": "integer",
            "minimum": 1,
            "maximum": 744
          },
          "sync": {
            "type": "object",
            "properties": {
              "importPolicy": {
                "default": "review",
                "type": "string",
                "enum": [
                  "review",
                  "preserve"
                ]
              }
            },
            "additionalProperties": false
          }
        },
        "required": [
          "baseUrl",
          "instanceId",
          "connectPolicy",
          "organisationAccounts",
          "schemes",
          "currencies"
        ],
        "additionalProperties": false,
        "description": "Integrated Finance connection configuration (non-secret; from the adapter schema in `@wirebloom/providers`)."
      },
      "IntegrationConnection": {
        "type": "object",
        "description": "A banking connection of the operator with its live integration state.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "name": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "environment": {
            "$ref": "#/components/schemas/ProviderEnvironment"
          },
          "status": {
            "$ref": "#/components/schemas/ConnectionLifecycle"
          },
          "role": {
            "type": "string",
            "enum": [
              "primary",
              "fallback"
            ]
          },
          "webhookRegistrationState": {
            "$ref": "#/components/schemas/WebhookRegistrationState"
          },
          "webhookPartnerState": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WebhookPartnerState"
              },
              {
                "type": "null"
              }
            ]
          },
          "healthy": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Last connection test / health check passed."
          },
          "lastHealthAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "breaker": {
            "type": "string",
            "enum": [
              "closed",
              "open",
              "unknown"
            ],
            "description": "Circuit breaker from the provider request log (`unknown` without calls in 10 minutes)."
          },
          "errorRate1h": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1
          },
          "lastEventAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "lastEventType": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventBacklog": {
            "type": "integer",
            "description": "Verified provider events not yet processed.",
            "minimum": 0
          },
          "oldestUnprocessedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "lastReconciliation": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "status": {
                "type": "string"
              },
              "startedAt": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "finishedAt": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "status",
              "startedAt",
              "finishedAt"
            ]
          },
          "openReconciliationExceptions": {
            "type": "integer",
            "minimum": 0
          },
          "checklist": {
            "type": [
              "object",
              "null"
            ],
            "description": "Activation checklist progress (applicable steps); null for the batch rail.",
            "properties": {
              "complete": {
                "type": "boolean"
              },
              "done": {
                "type": "integer",
                "minimum": 0
              },
              "total": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "complete",
              "done",
              "total"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "provider",
          "environment",
          "status",
          "role",
          "webhookRegistrationState",
          "webhookPartnerState",
          "healthy",
          "lastHealthAt",
          "breaker",
          "errorRate1h",
          "lastEventAt",
          "lastEventType",
          "eventBacklog",
          "oldestUnprocessedAt",
          "lastReconciliation",
          "openReconciliationExceptions",
          "checklist"
        ]
      },
      "IntegrationHome": {
        "type": "object",
        "description": "Integration home of an operator (FR-PLAT-06): connections, webhook registration, API keys, usage, integrator webhooks and portal links.",
        "properties": {
          "operatorId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "generatedAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "activeConnectionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Active primary connection (production first).",
            "format": "uuid"
          },
          "connections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationConnection"
            },
            "description": "Connections not retired, active first."
          },
          "apiKeys": {
            "type": "object",
            "description": "Unrevoked, unexpired keys of the operator (all customers and operator-level).",
            "properties": {
              "active": {
                "type": "integer",
                "minimum": 0
              },
              "live": {
                "type": "integer",
                "minimum": 0
              },
              "test": {
                "type": "integer",
                "minimum": 0
              },
              "operatorLevel": {
                "type": "integer",
                "minimum": 0
              },
              "usedLast24h": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "active",
              "live",
              "test",
              "operatorLevel",
              "usedLast24h"
            ]
          },
          "usageLast7Days": {
            "$ref": "#/components/schemas/ApiUsageTotals"
          },
          "integratorWebhooks": {
            "type": "object",
            "properties": {
              "endpoints": {
                "type": "integer",
                "minimum": 0
              },
              "active": {
                "type": "integer",
                "minimum": 0
              },
              "paused": {
                "type": "integer",
                "minimum": 0
              },
              "failed": {
                "type": "integer",
                "minimum": 0
              },
              "deliveriesPending": {
                "type": "integer",
                "minimum": 0
              },
              "deliveriesFailed24h": {
                "type": "integer",
                "minimum": 0
              },
              "lastDeliveryAt": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "endpoints",
              "active",
              "paused",
              "failed",
              "deliveriesPending",
              "deliveriesFailed24h",
              "lastDeliveryAt"
            ]
          },
          "links": {
            "type": "object",
            "description": "Developer portal (`DEVELOPER_PORTAL_URL`, D-35, D-42).",
            "properties": {
              "portal": {
                "type": "string",
                "format": "uri"
              },
              "reference": {
                "type": "string",
                "format": "uri"
              },
              "gettingStarted": {
                "type": "string",
                "format": "uri"
              },
              "sandbox": {
                "type": "string",
                "format": "uri"
              },
              "changelog": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "portal",
              "reference",
              "gettingStarted",
              "sandbox",
              "changelog",
              "openapi"
            ]
          }
        },
        "required": [
          "operatorId",
          "generatedAt",
          "activeConnectionId",
          "connections",
          "apiKeys",
          "usageLast7Days",
          "integratorWebhooks",
          "links"
        ]
      },
      "IntegratorEvent": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "type": {
            "$ref": "#/components/schemas/IntegratorEventType"
          },
          "createdAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "apiVersion": {
            "type": "string",
            "const": "v1"
          },
          "tenantId": {
            "$ref": "#/components/schemas/Uuid",
            "description": "The endpoint's tenant: the customer id for customer-level endpoints, the operator id for operator-level endpoints."
          },
          "data": {
            "type": "object",
            "description": "Thin payload: fetch the full resource with the API (`GET /payments/{id}` …) using the id.",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "payment",
                  "transfer",
                  "exchange",
                  "incoming_payment",
                  "recipient",
                  "approval",
                  "funds_request",
                  "statement",
                  "balance",
                  "customer",
                  "compliance_hold"
                ]
              },
              "id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "status": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "previousStatus": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "test": {
                "type": "boolean",
                "description": "`true` on `POST /integrator-webhooks/{webhookId}/test` events (also header `WireBloom-Test: true`)."
              },
              "sandbox": {
                "type": "boolean",
                "description": "`true` on events simulated through `/sandbox/*`."
              },
              "related": {
                "type": "object",
                "description": "`compliance_hold.*`: the held payment or incoming payment.",
                "properties": {
                  "object": {
                    "type": "string",
                    "enum": [
                      "payment",
                      "incoming_payment"
                    ]
                  },
                  "id": {
                    "$ref": "#/components/schemas/Uuid"
                  }
                },
                "required": [
                  "object",
                  "id"
                ]
              }
            },
            "required": [
              "object",
              "id"
            ]
          },
          "customerId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid",
                "description": "The customer the event concerns (also on customer-level deliveries)."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "type",
          "createdAt",
          "apiVersion",
          "tenantId",
          "data"
        ],
        "examples": [
          {
            "id": "0192a6f3-0000-7000-8000-0000000e0001",
            "type": "payment.status_changed",
            "createdAt": "2026-09-23T11:02:00Z",
            "apiVersion": "v1",
            "tenantId": "0192a6f0-0000-7000-8000-0000000000c1",
            "data": {
              "object": "payment",
              "id": "0192a6f1-3333-7000-8000-00000000c001",
              "status": "completed",
              "previousStatus": "processing",
              "amount": {
                "amountMinor": "100000",
                "currency": "EUR"
              }
            }
          }
        ]
      },
      "IntegratorEventType": {
        "type": "string",
        "enum": [
          "webhook.test",
          "payment.created",
          "payment.status_changed",
          "payment.completed",
          "payment.failed",
          "payment.returned",
          "transfer.completed",
          "exchange.completed",
          "incoming_payment.received",
          "recipient.status_changed",
          "recipient.verification_completed",
          "approval.requested",
          "approval.decided",
          "funds_request.status_changed",
          "statement.available",
          "balance.low",
          "customer.created",
          "customer.status_changed",
          "customer.provisioning_blocked",
          "customer.provisioning_released",
          "compliance_hold.opened",
          "compliance_hold.decided",
          "balance.details_changed"
        ],
        "description": "`webhook.test` is sent only by `POST /integrator-webhooks/{webhookId}/test` (with `data.test: true` and header `WireBloom-Test: true`); endpoints cannot subscribe to it. Operator-level endpoints only (P9-T08b; `422 event_not_allowed` on customer endpoints): `customer.created`, `customer.status_changed`, `customer.provisioning_blocked`, `customer.provisioning_released`, `compliance_hold.opened`, `compliance_hold.decided`. `balance.details_changed` (P10-T04): the account identifier of a balance changed (VIBAN re-issue, provider switch or closure); `data.status` is the reason (`reissue`, `provider_switch`, `closing`); fetch `GET /account-identifiers` for the new details."
      },
      "IntegratorWebhook": {
        "type": "object",
        "description": "Integrator webhook endpoint (`tenant.integrator_webhooks`). Customer-level endpoints receive the customer's events; operator-level endpoints (created with `X-Tenant-Id` = the operator, P9-T08b) receive the events of every customer of the operator, including the operator-only types.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "url": {
            "type": "string",
            "format": "uri",
            "examples": [
              "https://erp.example.com/wirebloom/webhooks"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegratorEventType"
            },
            "minItems": 1
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "enabled": {
            "type": "boolean"
          },
          "secretPrefix": {
            "type": "string",
            "examples": [
              "whsec_Yt3"
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true,
            "description": "Row version: the ETag is `W/\"<updatedAt epoch ms>\"` (`If-Match` on `PATCH`)."
          },
          "lastDeliveryAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "failureCount": {
            "type": "integer",
            "minimum": 0,
            "readOnly": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "failed"
            ],
            "description": "`paused` after 20 consecutive failed attempts or `enabled: false`; `failed` when a delivery exhausts 72 h without success. Re-enable with `PATCH enabled: true`.",
            "readOnly": true
          },
          "pauseReason": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "consecutive_failures"
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "url",
          "events",
          "enabled",
          "secretPrefix",
          "createdAt",
          "updatedAt",
          "failureCount"
        ]
      },
      "IntegratorWebhookCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/IntegratorWebhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "Signing secret `whsec_...`, shown once."
              }
            },
            "required": [
              "secret"
            ]
          }
        ]
      },
      "IntegratorWebhookPage": {
        "type": "object",
        "description": "Cursor-paginated list of IntegratorWebhook.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegratorWebhook"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "IntegratorWebhookWrite": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegratorEventType"
            },
            "minItems": 1
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "url",
          "events"
        ],
        "additionalProperties": false
      },
      "Job": {
        "type": "object",
        "description": "Asynchronous job (exports, reports). Poll `GET /jobs/{jobId}`.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "export",
              "statement",
              "report",
              "bulk_validation",
              "billing_run",
              "reconciliation",
              "replay"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed",
              "cancelled"
            ]
          },
          "progress": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "resultUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pre-signed download URL (valid 15 minutes) when `status=succeeded`.",
            "format": "uri"
          },
          "error": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Problem"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "finishedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "kind",
          "status",
          "createdAt"
        ]
      },
      "JournalEntryKind": {
        "type": "string",
        "enum": [
          "payment",
          "incoming",
          "transfer",
          "exchange",
          "fee",
          "adjustment",
          "reversal",
          "hold_release",
          "card",
          "interest",
          "opening_balance"
        ]
      },
      "JournalLine": {
        "type": "object",
        "properties": {
          "entryId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "lineNo": {
            "type": "integer"
          },
          "postedAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "valueDate": {
            "$ref": "#/components/schemas/Date"
          },
          "kind": {
            "$ref": "#/components/schemas/JournalEntryKind"
          },
          "direction": {
            "$ref": "#/components/schemas/PostingDirection"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "runningBalance": {
            "$ref": "#/components/schemas/Money"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": "string"
          },
          "subject": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "type": {
                "type": "string"
              },
              "id": {
                "$ref": "#/components/schemas/Uuid"
              }
            },
            "required": [
              "type",
              "id"
            ]
          }
        },
        "required": [
          "entryId",
          "lineNo",
          "postedAt",
          "valueDate",
          "kind",
          "direction",
          "amount",
          "runningBalance",
          "description"
        ]
      },
      "JournalLinePage": {
        "type": "object",
        "description": "Cursor-paginated list of JournalLine.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JournalLine"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "KybCase": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/KybCaseStatus"
              }
            ],
            "readOnly": true
          },
          "provider": {
            "$ref": "#/components/schemas/KycProviderId"
          },
          "applicantId": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "company": {
            "type": "object",
            "properties": {
              "legalName": {
                "type": "string"
              },
              "tradingName": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "registrationNumber": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "incorporationCountry": {
                "$ref": "#/components/schemas/CountryCode"
              },
              "incorporationDate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "legalForm": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "website": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri"
              },
              "industryCode": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "SIC/NACE code."
              },
              "taxId": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "expectedActivity": {
            "type": "object",
            "properties": {
              "monthlyVolume": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "monthlyTransactions": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0
              },
              "currencies": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CurrencyCode"
                }
              },
              "countries": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CountryCode"
                }
              },
              "purpose": {
                "type": [
                  "string",
                  "null"
                ],
                "maxLength": 1000
              },
              "sourceOfFunds": {
                "type": [
                  "string",
                  "null"
                ],
                "maxLength": 1000
              }
            }
          },
          "steps": {
            "type": "object",
            "description": "Wizard completion flags.",
            "properties": {
              "company": {
                "type": "boolean"
              },
              "addresses": {
                "type": "boolean"
              },
              "ownership": {
                "type": "boolean"
              },
              "activity": {
                "type": "boolean"
              },
              "documents": {
                "type": "boolean"
              },
              "personal": {
                "type": "boolean",
                "description": "Sole traders and individuals only: the personal details are complete."
              }
            }
          },
          "result": {
            "type": [
              "object",
              "null"
            ],
            "description": "KYC provider outcome (read-only; staff only for `details`).",
            "properties": {
              "reviewAnswer": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "green",
                  "red",
                  "retry"
                ]
              },
              "screeningHits": {
                "type": "integer",
                "minimum": 0
              },
              "details": {
                "$ref": "#/components/schemas/KybProviderResult"
              }
            }
          },
          "infoRequested": {
            "type": [
              "string",
              "null"
            ]
          },
          "submittedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "reviewedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "customerType": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CustomerType"
              }
            ],
            "readOnly": true
          },
          "personal": {
            "$ref": "#/components/schemas/KybPersonal"
          },
          "mode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OnboardingMode"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "customerId",
          "status",
          "provider",
          "steps",
          "createdAt"
        ],
        "description": "P10-T03: for `sole_trader` / `individual` the wizard asks for `personal`, (sole traders) the business `company.tradingName` and `company.incorporationCountry`, expected activity and the clean documents `kyb_person_id` + `kyb_proof_of_address`; `ownership` is always complete. The KYC applicant is an individual applicant (the operator's individual level) created from `personal`; its review drives the case like a company review, and approval needs it GREEN when `kyb.requireAllPersonsVerified` is on (`409 kyc_incomplete`)."
      },
      "KybCaseStatus": {
        "type": "string",
        "enum": [
          "draft",
          "submitted",
          "in_review",
          "info_requested",
          "approved",
          "declined",
          "on_hold"
        ],
        "description": "ASSUMPTION: mirrors CustomerStatus onboarding subset; DATABASE.md `kyb_cases.status` is untyped."
      },
      "KybPersonal": {
        "type": "object",
        "description": "P10-T03 (FR-ONB-07): the natural person behind a sole-trader or individual customer. Account holders are adults (`422 under_age`). The residential address completes the `addresses` step.",
        "properties": {
          "firstName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "middleName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "dateOfBirth": {
            "$ref": "#/components/schemas/Date"
          },
          "nationality": {
            "$ref": "#/components/schemas/CountryCode"
          },
          "email": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Email"
              },
              {
                "type": "null"
              }
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\+[1-9][0-9]{6,14}$"
          },
          "residentialAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "taxId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional tax identification number.",
            "maxLength": 50
          },
          "taxCountry": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CountryCode"
              },
              {
                "type": "null"
              }
            ]
          },
          "occupation": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "pepDeclared": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Politically exposed person self-declaration."
          }
        },
        "additionalProperties": false
      },
      "KybProviderResult": {
        "type": "object",
        "description": "Stored KYC provider outcome of the company applicant (`tenant.kyb_cases.result`), merged from provider webhooks and syncs. Provider-specific keys may be added.",
        "properties": {
          "outcome": {
            "type": "string",
            "description": "Normalised outcome (`approved`, `rejected`, `retry`, `pending` …)."
          },
          "review": {
            "type": "object",
            "description": "Provider review block (Sumsub `reviewResult`); extra provider keys are kept.",
            "properties": {
              "reviewStatus": {
                "type": [
                  "string",
                  "null"
                ],
                "examples": [
                  "completed"
                ]
              },
              "answer": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Provider review answer (Sumsub `GREEN` / `RED`).",
                "examples": [
                  "GREEN"
                ]
              },
              "rejectType": {
                "type": [
                  "string",
                  "null"
                ],
                "examples": [
                  "RETRY",
                  "FINAL"
                ]
              }
            }
          },
          "rejectLabels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Provider reject labels (e.g. `DOCUMENT_PAGE_MISSING`)."
          },
          "eventType": {
            "type": "string",
            "description": "Provider event that last updated the result (e.g. `applicantReviewed`)."
          },
          "at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        },
        "additionalProperties": true
      },
      "KycProviderId": {
        "type": "string",
        "enum": [
          "sumsub"
        ]
      },
      "Mandate": {
        "type": "object",
        "description": "Counterparty account identifiers are returned masked.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "direction": {
            "$ref": "#/components/schemas/MandateDirection"
          },
          "scheme": {
            "$ref": "#/components/schemas/MandateScheme"
          },
          "reference": {
            "type": "string",
            "maxLength": 35
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "counterparty": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "iban": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "accountNumber": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "sortCode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "bic": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "creditorId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "address": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Address"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "name"
            ]
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MandateStatus"
              }
            ],
            "readOnly": true
          },
          "signedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "cancelledAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "providerRef": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "management": {
            "type": "string",
            "enum": [
              "client",
              "provider"
            ],
            "description": "`client`: WireBloom generates collection files / status reports are entered by staff; `provider`: the partner manages the mandate.",
            "readOnly": true
          },
          "statusReason": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "lastCollectionAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "customerId",
          "direction",
          "scheme",
          "reference",
          "balanceId",
          "counterparty",
          "status",
          "createdAt"
        ]
      },
      "MandateCreate": {
        "type": "object",
        "properties": {
          "direction": {
            "$ref": "#/components/schemas/MandateDirection"
          },
          "scheme": {
            "$ref": "#/components/schemas/MandateScheme"
          },
          "reference": {
            "type": "string",
            "description": "Mandate reference (UMR); empty generates one (`WB` + 14 characters).",
            "maxLength": 35
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "counterparty": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "iban": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "accountNumber": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "sortCode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "bic": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "creditorId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "address": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Address"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "name"
            ]
          },
          "signedAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "mandateDocumentId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "direction",
          "scheme",
          "reference",
          "balanceId",
          "counterparty"
        ],
        "additionalProperties": false
      },
      "MandateDirection": {
        "type": "string",
        "enum": [
          "collect",
          "pay"
        ]
      },
      "MandatePage": {
        "type": "object",
        "description": "Cursor-paginated list of Mandate.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Mandate"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "MandateScheme": {
        "type": "string",
        "enum": [
          "sepa_dd_core",
          "sepa_dd_b2b",
          "bacs_dd"
        ]
      },
      "MandateSign": {
        "type": "object",
        "description": "Records the debtor's signature of a pending mandate (`pending` → `active`).",
        "properties": {
          "signedAt": {
            "$ref": "#/components/schemas/Date"
          },
          "mandateDocumentId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "signedAt"
        ],
        "additionalProperties": false
      },
      "MandateStatus": {
        "type": "string",
        "enum": [
          "pending",
          "active",
          "cancelled",
          "failed",
          "expired"
        ],
        "description": "ASSUMPTION: untyped in DATABASE.md."
      },
      "Metadata": {
        "type": "object",
        "maxProperties": 20,
        "propertyNames": {
          "pattern": "^[A-Za-z0-9_-]{1,40}$"
        },
        "additionalProperties": {
          "type": "string",
          "maxLength": 500
        },
        "description": "Integrator attributes (parity P-10): at most 20 string keys (`[A-Za-z0-9_-]{1,40}`), values up to 500 characters without control characters, 8 KiB in total. Returned on reads; list filter `filter[metadata.<key>]=<value>`.",
        "examples": [
          {
            "orderId": "A-17",
            "costCentre": "ops"
          }
        ]
      },
      "MetadataPatch": {
        "type": "object",
        "maxProperties": 20,
        "propertyNames": {
          "pattern": "^[A-Za-z0-9_-]{1,40}$"
        },
        "additionalProperties": {
          "type": [
            "string",
            "null"
          ],
          "maxLength": 500
        },
        "description": "Merge patch of `Metadata`: a string sets the key, `null` removes it; the merged map must stay within the limits (`422`)."
      },
      "Money": {
        "type": "object",
        "description": "Monetary amount in integer minor units with an ISO 4217 currency. `{\"amountMinor\":\"125050\",\"currency\":\"GBP\"}` is GBP 1,250.50. Currencies with 0 or 3 decimals follow ISO 4217 exponents.",
        "properties": {
          "amountMinor": {
            "$ref": "#/components/schemas/AmountMinor"
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          }
        },
        "required": [
          "amountMinor",
          "currency"
        ],
        "examples": [
          {
            "amountMinor": "125050",
            "currency": "GBP"
          }
        ]
      },
      "OnboardingMode": {
        "type": "string",
        "enum": [
          "prepare",
          "live"
        ],
        "description": "`prepare`: wizard editable, identity verification hidden, submission refused (`409 onboarding-not-open`); `live`: full KYB/KYC flow."
      },
      "PageInfo": {
        "type": "object",
        "description": "Cursor pagination metadata.",
        "properties": {
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque cursor for the next page; `null` on the last page.",
            "examples": [
              "eyJjIjoiMjAyNi0wOS0yM1QxMDoxNTozMFoiLCJpIjoiMDE5MiJ9"
            ]
          },
          "prevCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque cursor for the previous page; `null` on the first page."
          },
          "limit": {
            "type": "integer",
            "description": "Page size applied.",
            "minimum": 1,
            "maximum": 100,
            "examples": [
              25
            ]
          },
          "total": {
            "type": "integer",
            "description": "Total matching items. Present only when cheap to compute (small collections) or when `withTotal=true` was requested on endpoints that allow it.",
            "minimum": 0
          }
        },
        "required": [
          "nextCursor",
          "prevCursor",
          "limit"
        ]
      },
      "Payment": {
        "type": "object",
        "description": "Outgoing payment. `amount` is what the recipient receives (recipient currency); `sendAmount` is debited from the source balance when currencies differ.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true,
            "description": "Also used as the provider idempotency key."
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "kind": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentKind"
              }
            ],
            "readOnly": true
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentStatus"
              }
            ],
            "readOnly": true
          },
          "statusReason": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "sourceBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "recipientId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "recipient": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/PaymentParty"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "sendAmount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "quoteId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "rate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Rate"
              },
              {
                "type": "null"
              }
            ]
          },
          "fees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeeLine"
            },
            "readOnly": true
          },
          "totalDebit": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "readOnly": true
          },
          "rail": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Rail"
              }
            ],
            "readOnly": true
          },
          "reference": {
            "type": "string",
            "maxLength": 140
          },
          "purposeCode": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 35
          },
          "chargeBearer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ChargeBearer"
              },
              {
                "type": "null"
              }
            ]
          },
          "urgent": {
            "type": "boolean"
          },
          "scheduledFor": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "estimatedArrival": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "attachmentDocumentIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          "approval": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "approvalId": {
                "$ref": "#/components/schemas/Uuid"
              },
              "requiredApprovals": {
                "type": "integer"
              },
              "approvalsReceived": {
                "type": "integer"
              },
              "status": {
                "$ref": "#/components/schemas/ApprovalStatus"
              }
            },
            "readOnly": true
          },
          "providerRef": {
            "type": [
              "string",
              "null"
            ],
            "description": "Provider reference (e.g. UETR for SWIFT).",
            "readOnly": true
          },
          "channel": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Channel"
              }
            ],
            "readOnly": true
          },
          "createdBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "apiKeyId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "submittedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "completedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "transactionId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "processing": {
            "$ref": "#/components/schemas/PaymentProcessing"
          }
        },
        "required": [
          "id",
          "customerId",
          "kind",
          "status",
          "sourceBalanceId",
          "amount",
          "fees",
          "totalDebit",
          "rail",
          "reference",
          "urgent",
          "channel",
          "createdAt"
        ],
        "examples": [
          {
            "id": "0192a6f1-3333-7000-8000-00000000c001",
            "customerId": "0192a6f0-0000-7000-8000-0000000000c1",
            "kind": "external",
            "status": "pending_approval",
            "sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
            "recipientId": "0192a6f1-2222-7000-8000-00000000a001",
            "recipient": {
              "name": "Acme GmbH",
              "maskedIdentifier": "DE89 •••• 3000",
              "bankCountry": "DE"
            },
            "amount": {
              "amountMinor": "100000",
              "currency": "EUR"
            },
            "sendAmount": {
              "amountMinor": "85630",
              "currency": "GBP"
            },
            "quoteId": "0192a6f1-4444-7000-8000-00000000d001",
            "rate": "1.1678000000",
            "fees": [
              {
                "code": "outgoing_xborder",
                "label": "Outgoing SEPA fee",
                "amount": {
                  "amountMinor": "150",
                  "currency": "GBP"
                }
              }
            ],
            "totalDebit": {
              "amountMinor": "85780",
              "currency": "GBP"
            },
            "rail": "sepa",
            "reference": "INV-2026-0042",
            "urgent": false,
            "approval": {
              "approvalId": "0192a6f1-5555-7000-8000-00000000a001",
              "requiredApprovals": 1,
              "approvalsReceived": 0,
              "status": "pending"
            },
            "channel": "web",
            "createdAt": "2026-09-23T10:20:00Z"
          }
        ]
      },
      "PaymentCreate": {
        "type": "object",
        "description": "Single-payment wizard: recipient → amount/currency → reference/purpose/attachments → date → review → submit. When `amount.currency` differs from the source balance, pass a live `quoteId` (or `fixedSide` to let the server quote).",
        "properties": {
          "sourceBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "recipientId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "fixedSide": {
            "$ref": "#/components/schemas/FixedSide"
          },
          "quoteId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "reference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "purposeCode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Purpose / transfer reason from `GET /payments/purpose-codes` (ISO 20022 `ExternalPurpose1Code`; CNH needs `GOD`, `STR`, `CTF` or `OTF`: `422 purpose_required` / `invalid_purpose`).",
            "maxLength": 35
          },
          "chargeBearer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ChargeBearer"
              },
              {
                "type": "null"
              }
            ]
          },
          "urgent": {
            "type": "boolean",
            "default": false
          },
          "scheduledFor": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "attachmentDocumentIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            },
            "maxItems": 5
          },
          "submit": {
            "type": "boolean",
            "description": "`false` saves a draft; `true` submits (approval, holds, routing).",
            "default": true
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "required": [
          "sourceBalanceId",
          "recipientId",
          "amount",
          "reference"
        ],
        "additionalProperties": false,
        "examples": [
          {
            "sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
            "recipientId": "0192a6f1-2222-7000-8000-00000000a001",
            "amount": {
              "amountMinor": "100000",
              "currency": "EUR"
            },
            "fixedSide": "buy",
            "quoteId": "0192a6f1-4444-7000-8000-00000000d001",
            "reference": "INV-2026-0042",
            "purposeCode": "SUPP",
            "urgent": false,
            "submit": true
          }
        ]
      },
      "PaymentDryRun": {
        "type": "object",
        "description": "Fees, route and checks preview for the Review step. No holds, no side effects.",
        "properties": {
          "rail": {
            "$ref": "#/components/schemas/Rail"
          },
          "connectionName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Shown to staff only."
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "sendAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "rate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Rate"
              },
              {
                "type": "null"
              }
            ]
          },
          "quoteId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "quoteExpiresAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "fees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeeLine"
            }
          },
          "totalDebit": {
            "$ref": "#/components/schemas/Money"
          },
          "estimatedArrival": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "earliestExecutionDate": {
            "$ref": "#/components/schemas/Date"
          },
          "cutOff": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "requiresApproval": {
            "type": "boolean"
          },
          "requiresStepUp": {
            "type": "boolean"
          },
          "stepUpAction": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/StepUpAction"
              },
              {
                "type": "null"
              }
            ]
          },
          "limitCheck": {
            "type": "object",
            "properties": {
              "withinLimits": {
                "type": "boolean"
              },
              "breaches": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "limit": {
                      "type": "string"
                    },
                    "remaining": {
                      "$ref": "#/components/schemas/Money"
                    }
                  }
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": [
          "rail",
          "amount",
          "sendAmount",
          "fees",
          "totalDebit",
          "estimatedArrival",
          "earliestExecutionDate",
          "requiresApproval",
          "requiresStepUp",
          "limitCheck",
          "warnings"
        ]
      },
      "PaymentEvent": {
        "type": "object",
        "description": "Status history (transaction drawer \"Updates\" tab).",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "fromStatus": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PaymentStatus"
              },
              {
                "type": "null"
              }
            ]
          },
          "toStatus": {
            "$ref": "#/components/schemas/PaymentStatus"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "actor": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "type": {
                "$ref": "#/components/schemas/AuditActorType"
              },
              "id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        },
        "required": [
          "id",
          "toStatus",
          "at"
        ]
      },
      "PaymentKind": {
        "type": "string",
        "enum": [
          "external",
          "internal",
          "exchange_leg"
        ]
      },
      "PaymentPage": {
        "type": "object",
        "description": "Cursor-paginated list of Payment.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Payment"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "PaymentParty": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "maskedIdentifier": {
            "type": [
              "string",
              "null"
            ]
          },
          "bankCountry": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CountryCode"
              },
              {
                "type": "null"
              }
            ]
          },
          "bic": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name"
        ]
      },
      "PaymentProcessing": {
        "type": "object",
        "description": "Queue state of an approved payment waiting behind a backlog (D-50). An estimate: the position counts approved, due payments of the same operator ahead of this one, and the time assumes the operator's share of the submission queue (capped per operator) keeps draining at its usual rate.",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "queued"
            ],
            "description": "Waiting in the submission queue for the hand-off to the bank."
          },
          "position": {
            "type": "integer",
            "description": "Place in the operator's submission queue; 1 = next.",
            "minimum": 1
          },
          "etaSeconds": {
            "type": "integer",
            "description": "Estimated seconds until the payment is handed to the bank.",
            "minimum": 0
          },
          "estimatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true,
            "description": "Estimated time of the hand-off to the bank."
          }
        },
        "required": [
          "status",
          "position",
          "etaSeconds",
          "estimatedAt"
        ]
      },
      "PaymentStatus": {
        "type": "string",
        "enum": [
          "draft",
          "pending_approval",
          "approved",
          "submitted",
          "processing",
          "completed",
          "failed",
          "returned",
          "cancelled",
          "on_hold",
          "exception"
        ]
      },
      "PaymentUpdate": {
        "type": "object",
        "description": "Only `draft` payments are editable.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "quoteId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "reference": {
            "type": "string",
            "maxLength": 140
          },
          "purposeCode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Purpose / transfer reason from `GET /payments/purpose-codes` (ISO 20022 `ExternalPurpose1Code`; CNH needs `GOD`, `STR`, `CTF` or `OTF`: `422 purpose_required` / `invalid_purpose`).",
            "maxLength": 35
          },
          "chargeBearer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ChargeBearer"
              },
              {
                "type": "null"
              }
            ]
          },
          "urgent": {
            "type": "boolean"
          },
          "scheduledFor": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "attachmentDocumentIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            },
            "maxItems": 5
          },
          "metadata": {
            "$ref": "#/components/schemas/MetadataPatch"
          }
        },
        "additionalProperties": false
      },
      "PlannedRun": {
        "type": "object",
        "description": "A planned run: the nominal date, the business day it executes on (holidays and cut-offs of the currency and rail) and the instant the worker runs it.",
        "properties": {
          "occurrenceDate": {
            "$ref": "#/components/schemas/Date"
          },
          "executionDate": {
            "$ref": "#/components/schemas/Date"
          },
          "runsAt": {
            "$ref": "#/components/schemas/Timestamp"
          }
        },
        "required": [
          "occurrenceDate",
          "executionDate",
          "runsAt"
        ]
      },
      "PositiveMoney": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Money"
          }
        ],
        "description": "Money whose `amountMinor` must be strictly positive.",
        "properties": {
          "amountMinor": {
            "type": "string",
            "pattern": "^[1-9][0-9]{0,18}$"
          }
        }
      },
      "PostingDirection": {
        "type": "string",
        "enum": [
          "debit",
          "credit"
        ]
      },
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. Served as `application/problem+json`.",
        "properties": {
          "type": {
            "type": "string",
            "description": "URI identifying the problem type. Documented at the URI. `about:blank` is never used.",
            "format": "uri",
            "examples": [
              "https://api.banking.wirebloom.com/problems/validation-error"
            ]
          },
          "title": {
            "type": "string",
            "description": "Short, stable summary of the problem type.",
            "examples": [
              "Validation failed"
            ]
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code.",
            "minimum": 400,
            "maximum": 599,
            "examples": [
              422
            ]
          },
          "detail": {
            "type": "string",
            "description": "Occurrence-specific explanation. Never contains secrets or internal identifiers of other tenants.",
            "examples": [
              "2 fields are invalid."
            ]
          },
          "instance": {
            "type": "string",
            "description": "URI reference identifying this occurrence (the request path plus request id).",
            "format": "uri-reference",
            "examples": [
              "/v1/payments#req_01J8Z6Q7R2"
            ]
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldError"
            },
            "description": "Field-level validation errors (present for 400/422)."
          },
          "requestId": {
            "type": "string",
            "description": "Value of `X-Request-Id` for this request; quote it to support.",
            "examples": [
              "req_01J8Z6Q7R2"
            ]
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable problem code (last path segment of `type`).",
            "examples": [
              "validation_error"
            ]
          },
          "retryAfterSeconds": {
            "type": "integer",
            "description": "For 409 idempotency-in-progress and 429 responses.",
            "minimum": 0
          },
          "stepUp": {
            "type": "object",
            "description": "Present when `type` is `.../step-up-required`.",
            "properties": {
              "action": {
                "$ref": "#/components/schemas/StepUpAction"
              },
              "challengeUrl": {
                "type": "string",
                "format": "uri-reference",
                "examples": [
                  "/v1/auth/step-up/challenges"
                ]
              }
            }
          },
          "reason": {
            "type": "string",
            "enum": [
              "idle",
              "revoked",
              "expired"
            ],
            "description": "`401 session-expired` only: why the session ended. `idle`: the idle limit (30 min staff, 60 min customers on the web); `revoked`: signed out, failed step-ups or a staff action; `expired`: absolute lifetime reached (mobile: refresh the access token, then sign in again if that fails)."
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "requestId"
        ],
        "examples": [
          {
            "type": "https://api.banking.wirebloom.com/problems/validation-error",
            "title": "Validation failed",
            "status": 422,
            "detail": "1 field is invalid.",
            "instance": "/v1/payments#req_01J8Z6Q7R2",
            "code": "validation_error",
            "requestId": "req_01J8Z6Q7R2",
            "errors": [
              {
                "field": "/amount/amountMinor",
                "code": "too_small",
                "message": "Amount must be greater than zero."
              }
            ]
          }
        ]
      },
      "ProviderConnection": {
        "type": "object",
        "description": "Per-tenant provider connection (ARCHITECTURE §6). Secrets are write-only. One `active` banking connection per operator and environment (D-32).",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "operatorId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "environment": {
            "$ref": "#/components/schemas/ProviderEnvironment"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "config": {
            "$ref": "#/components/schemas/ProviderConnectionConfig"
          },
          "credentialsSet": {
            "type": "boolean",
            "description": "Whether credentials are stored. Credentials are never returned.",
            "readOnly": true
          },
          "credentialsKid": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          },
          "credentialsUpdatedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "credentialsFingerprint": {
            "type": [
              "string",
              "null"
            ],
            "description": "Salted HMAC fingerprint (`fp_` + 12 hex) so staff can tell credential sets apart without seeing them.",
            "readOnly": true
          },
          "webhookSecretSet": {
            "type": "boolean",
            "readOnly": true
          },
          "webhookUrl": {
            "type": "string",
            "description": "Register this URL with the provider.",
            "format": "uri",
            "examples": [
              "https://api.banking.wirebloom.com/v1/webhooks/banking-circle/3kq9..."
            ],
            "readOnly": true
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ConnectionLifecycle"
              }
            ],
            "readOnly": true
          },
          "role": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ConnectionRole"
              }
            ],
            "readOnly": true
          },
          "fallbackCurrencies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CurrencyCode"
            },
            "description": "Currencies a `fallback` connection carries; empty for primaries.",
            "readOnly": true
          },
          "contractModel": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/ContractModel"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "webhookRegistrationState": {
            "allOf": [
              {
                "$ref": "#/components/schemas/WebhookRegistrationState"
              }
            ],
            "readOnly": true
          },
          "healthy": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Health flag from the last health check (`error` is not a lifecycle state, D-32).",
            "readOnly": true
          },
          "verifiedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "activatedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "drainingAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "retiredAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "capabilities": {
            "type": "object",
            "properties": {
              "virtualAccounts": {
                "type": "boolean"
              },
              "realAccounts": {
                "type": "boolean"
              },
              "sepa": {
                "type": "boolean"
              },
              "sepaInstant": {
                "type": "boolean"
              },
              "swift": {
                "type": "boolean"
              },
              "fasterPayments": {
                "type": "boolean"
              },
              "chaps": {
                "type": "boolean"
              },
              "bacs": {
                "type": "boolean"
              },
              "returns": {
                "type": "boolean"
              },
              "statementsCamt053": {
                "type": "boolean"
              },
              "currencies": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CurrencyCode"
                }
              },
              "fx": {
                "type": "boolean"
              },
              "forwards": {
                "type": "boolean"
              },
              "heldRates": {
                "type": "boolean"
              },
              "cards": {
                "type": "boolean"
              },
              "webhooks": {
                "type": "boolean"
              },
              "cop": {
                "type": "boolean"
              },
              "vop": {
                "type": "boolean"
              },
              "directDebit": {
                "type": "boolean"
              },
              "bulk": {
                "type": "boolean"
              },
              "recalls": {
                "type": "boolean"
              }
            },
            "readOnly": true
          },
          "lastHealthAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "lastHealth": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "latencyMs": {
                "type": "integer"
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "operatorId",
          "provider",
          "environment",
          "name",
          "config",
          "credentialsSet",
          "webhookUrl",
          "status",
          "role",
          "fallbackCurrencies",
          "contractModel",
          "webhookRegistrationState",
          "createdAt"
        ]
      },
      "ProviderConnectionConfig": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/BankingCircleConnectionConfig"
          },
          {
            "$ref": "#/components/schemas/BatchCsvConnectionConfig"
          },
          {
            "$ref": "#/components/schemas/IntegratedFinanceConnectionConfig"
          },
          {
            "$ref": "#/components/schemas/SandboxConnectionConfig"
          }
        ],
        "description": "Non-secret configuration of the connection's provider (`provider` selects the schema; `GET /provider-catalogue` serves the same JSON Schemas)."
      },
      "ProviderConnectionPage": {
        "type": "object",
        "description": "Cursor-paginated list of ProviderConnection.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProviderConnection"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "ProviderEnvironment": {
        "type": "string",
        "enum": [
          "sandbox",
          "production"
        ]
      },
      "ProviderId": {
        "type": "string",
        "enum": [
          "banking_circle",
          "integrated_finance",
          "batch_csv",
          "sandbox"
        ],
        "description": "Banking provider (DATABASE.md `platform.provider_catalogue.provider`)."
      },
      "PurposeCode": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "scheme": {
            "type": "string",
            "enum": [
              "iso20022",
              "cnh"
            ]
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "scheme",
          "label"
        ]
      },
      "PurposeCodeCatalogue": {
        "type": "object",
        "properties": {
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "country": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CountryCode"
              },
              {
                "type": "null"
              }
            ]
          },
          "rail": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Rail"
              },
              {
                "type": "null"
              }
            ]
          },
          "required": {
            "type": "boolean",
            "description": "A purpose code must be sent with payments in this context (e.g. CNH)."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "codes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PurposeCode"
            }
          },
          "routingCode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Domestic routing code the destination needs (`aba`, `transit`, `clabe`, `bsb`, `ifsc`, `cnaps`, `sortCode`); null for IBAN countries."
          },
          "railLabel": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "currency",
          "country",
          "rail",
          "required",
          "reason",
          "codes",
          "routingCode",
          "railLabel"
        ]
      },
      "Quote": {
        "type": "object",
        "description": "Firm quote; typically valid 30 seconds (countdown in the UI). Refresh to get a new rate.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "sellAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "buyAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "rate": {
            "$ref": "#/components/schemas/Rate"
          },
          "inverseRate": {
            "$ref": "#/components/schemas/Rate"
          },
          "fixedSide": {
            "$ref": "#/components/schemas/FixedSide"
          },
          "kind": {
            "$ref": "#/components/schemas/ExchangeKind"
          },
          "fee": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "settlementDate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "depositRequired": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "expiresAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "used": {
            "type": "boolean"
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "sellAmount",
          "buyAmount",
          "rate",
          "inverseRate",
          "fixedSide",
          "kind",
          "expiresAt",
          "used",
          "createdAt"
        ],
        "examples": [
          {
            "id": "0192a6f1-4444-7000-8000-00000000d001",
            "sellAmount": {
              "amountMinor": "85630",
              "currency": "GBP"
            },
            "buyAmount": {
              "amountMinor": "100000",
              "currency": "EUR"
            },
            "rate": "1.1678000000",
            "inverseRate": "0.8563000000",
            "fixedSide": "buy",
            "kind": "spot",
            "expiresAt": "2026-09-23T10:20:30Z",
            "used": false,
            "createdAt": "2026-09-23T10:20:00Z"
          }
        ]
      },
      "QuoteCreate": {
        "type": "object",
        "description": "`amount.currency` must equal the fixed side currency. `settlementDate` required for `forward`.",
        "properties": {
          "sellCurrency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "buyCurrency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "fixedSide": {
            "$ref": "#/components/schemas/FixedSide"
          },
          "kind": {
            "$ref": "#/components/schemas/ExchangeKind"
          },
          "settlementDate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Date"
              },
              {
                "type": "null"
              }
            ]
          },
          "sellBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "buyBalanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "holdMinutes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Held rates: how long the rate is held (default: operator setting `exchange.heldRateDefaultMinutes`).",
            "minimum": 1,
            "maximum": 1440
          }
        },
        "required": [
          "sellCurrency",
          "buyCurrency",
          "amount",
          "fixedSide"
        ],
        "additionalProperties": false,
        "examples": [
          {
            "sellCurrency": "GBP",
            "buyCurrency": "EUR",
            "amount": {
              "amountMinor": "100000",
              "currency": "EUR"
            },
            "fixedSide": "buy",
            "kind": "spot"
          }
        ]
      },
      "Rail": {
        "type": "string",
        "enum": [
          "sepa",
          "sepa_instant",
          "swift",
          "faster_payments",
          "chaps",
          "bacs",
          "target2",
          "ach",
          "wire",
          "eft",
          "local",
          "internal"
        ],
        "description": "`bacs`: UK Bacs credits where the routed partner supports it. P10-T03 (FR-PAY-13): `target2` (EUR RTGS, Banking Circle `URGP`), `ach` (US ACH), `wire` (US Fedwire) and `eft` (Canadian EFT) are capability-gated: usable only when the active connection reports them."
      },
      "Rate": {
        "type": "string",
        "description": "Decimal FX rate as a string (up to 10 decimal places), buy units per one sell unit.",
        "pattern": "^[0-9]{1,10}(\\.[0-9]{1,10})?$",
        "examples": [
          "1.1684500000"
        ]
      },
      "Recipient": {
        "type": "object",
        "description": "Recipient. `approval` is the recipient's review as the caller sees it (null when it was never reviewed). Full bank identifiers are returned only on `GET /recipients/{id}` (and on create/update); list responses carry `bank.iban` and `bank.accountNumber` as `null` and show `maskedIdentifier` instead.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "type": {
            "$ref": "#/components/schemas/RecipientType"
          },
          "name": {
            "type": "string",
            "maxLength": 140
          },
          "nickname": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          },
          "email": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Email"
              },
              {
                "type": "null"
              }
            ]
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "bank": {
            "$ref": "#/components/schemas/RecipientBank"
          },
          "maskedIdentifier": {
            "type": "string",
            "description": "Masked IBAN/account number for lists.",
            "examples": [
              "GB33 •••• 5555"
            ],
            "readOnly": true
          },
          "defaultReference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 35
          },
          "purpose": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RecipientStatus"
              }
            ],
            "readOnly": true
          },
          "verification": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/RecipientVerification"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "lastPaidAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "createdBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "approval": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/RecipientApproval"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "required": [
          "id",
          "customerId",
          "type",
          "name",
          "currency",
          "bank",
          "maskedIdentifier",
          "status",
          "createdAt",
          "approval"
        ],
        "examples": [
          {
            "id": "0192a6f1-2222-7000-8000-00000000a001",
            "customerId": "0192a6f0-0000-7000-8000-0000000000c1",
            "type": "company",
            "name": "Acme GmbH",
            "nickname": "Acme",
            "email": "ap@acme.de",
            "currency": "EUR",
            "bank": {
              "iban": "DE89370400440532013000",
              "bic": "COBADEFFXXX",
              "bankName": "Commerzbank",
              "bankCountry": "DE"
            },
            "maskedIdentifier": "DE89 •••• 3000",
            "defaultReference": "INV-2026",
            "purpose": "Supplier payment",
            "status": "approved",
            "verification": {
              "scheme": "vop",
              "outcome": "match",
              "provider": "banking_circle",
              "verifiedAt": "2026-09-23T10:16:00Z"
            },
            "createdAt": "2026-09-23T10:15:30Z",
            "approval": null
          }
        ]
      },
      "RecipientApproval": {
        "type": "object",
        "description": "The review of a recipient (`Recipient.approval`, P6-T01).",
        "properties": {
          "approvalId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `tenant.approvals` request (customer approval mode); null in operator / `none` mode. Decide with `POST /recipients/{id}/approve|decline`.",
            "format": "uuid"
          },
          "mode": {
            "type": "string",
            "enum": [
              "customer",
              "operator",
              "none"
            ],
            "description": "Operator recipient approval mode the review ran in (D-14)."
          },
          "status": {
            "$ref": "#/components/schemas/ApprovalStatus"
          },
          "tier": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "requiredApprovals": {
            "type": "integer",
            "minimum": 1
          },
          "received": {
            "type": "integer",
            "description": "Approvals received so far.",
            "minimum": 0
          },
          "decisions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "by": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "byName": {
                  "type": "string"
                },
                "decision": {
                  "type": "string",
                  "enum": [
                    "approved",
                    "rejected"
                  ]
                },
                "comment": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "at": {
                  "$ref": "#/components/schemas/Timestamp"
                }
              },
              "required": [
                "by",
                "byName",
                "decision",
                "comment",
                "at"
              ]
            }
          },
          "canDecide": {
            "type": "boolean",
            "description": "Whether the caller may approve or decline now (eligible customer approver, not the requester unless self-approval is allowed, not decided yet). Operator-mode (and `none`-mode) reviews: true for operator staff holding `recipients.approve` while the review is pending (P9-T03); false for customer members."
          },
          "expiresAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "approvalId",
          "mode",
          "status",
          "tier",
          "requiredApprovals",
          "received",
          "decisions",
          "canDecide",
          "expiresAt"
        ]
      },
      "RecipientBank": {
        "type": "object",
        "properties": {
          "iban": {
            "type": [
              "string",
              "null"
            ]
          },
          "accountNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "bic": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[A-Z0-9]{8}([A-Z0-9]{3})?$"
          },
          "routingCodes": {
            "type": "object",
            "description": "National routing codes (P10-T03, parity P-44; Integrated Finance keys in brackets): `sortCode` (sort-code), `aba`, `transit` (rtn-canada; 8 digits or the 9-digit routing number), `clabe`, `bsb` (bsb-code), `ifsc`, `cnaps`, `bankCode` (bank-code), `branchCode` (branch-code). Formats and check digits (ABA, CLABE) are validated.",
            "propertyNames": {
              "pattern": "^(sortCode|aba|transit|clabe|bsb|ifsc|cnaps|bankCode|branchCode)$"
            },
            "additionalProperties": {
              "type": "string"
            }
          },
          "bankName": {
            "type": [
              "string",
              "null"
            ]
          },
          "bankAddress": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "bankCountry": {
            "$ref": "#/components/schemas/CountryCode"
          },
          "accountType": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "checking",
              "savings"
            ]
          }
        },
        "required": [
          "bankCountry"
        ]
      },
      "RecipientCreate": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/RecipientType"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "nickname": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          },
          "email": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Email"
              },
              {
                "type": "null"
              }
            ]
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "bank": {
            "$ref": "#/components/schemas/RecipientBank"
          },
          "defaultReference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 35
          },
          "purpose": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          },
          "verificationOverride": {
            "type": [
              "object",
              "null"
            ],
            "description": "Proceed despite `close_match`/`no_match` when policy allows.",
            "properties": {
              "acceptOutcome": {
                "$ref": "#/components/schemas/VerificationOutcome"
              },
              "reason": {
                "type": "string",
                "minLength": 3,
                "maxLength": 500
              }
            },
            "required": [
              "acceptOutcome",
              "reason"
            ]
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "required": [
          "type",
          "name",
          "currency",
          "bank"
        ],
        "additionalProperties": false,
        "examples": [
          {
            "type": "company",
            "name": "Acme GmbH",
            "currency": "EUR",
            "bank": {
              "iban": "DE89370400440532013000",
              "bic": "COBADEFFXXX",
              "bankCountry": "DE"
            },
            "defaultReference": "INV-2026"
          }
        ]
      },
      "RecipientPage": {
        "type": "object",
        "description": "Cursor-paginated list of Recipient.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Recipient"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "RecipientRequirementField": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "description": "Body path, e.g. `bank.iban`, `bank.routingCodes.sortCode`, `address.postalCode`."
          },
          "label": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "string",
              "enum",
              "country",
              "date"
            ]
          },
          "required": {
            "type": "boolean"
          },
          "pattern": {
            "type": [
              "string",
              "null"
            ]
          },
          "minLength": {
            "type": [
              "integer",
              "null"
            ]
          },
          "maxLength": {
            "type": [
              "integer",
              "null"
            ]
          },
          "enum": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                }
              }
            }
          },
          "validation": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "iban_mod97",
              "bic",
              "sort_code",
              "aba",
              "clabe",
              "ifsc",
              "bsb",
              "transit",
              "cnaps"
            ]
          },
          "example": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "path",
          "label",
          "type",
          "required"
        ]
      },
      "RecipientRequirements": {
        "type": "object",
        "description": "Dynamic form definition for the Add-recipient wizard, derived from routing and the routed provider (FR-REC-01).",
        "properties": {
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "bankCountry": {
            "$ref": "#/components/schemas/CountryCode"
          },
          "recipientType": {
            "$ref": "#/components/schemas/RecipientType"
          },
          "rails": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Rail"
            }
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecipientRequirementField"
            }
          },
          "verificationAvailable": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "cop",
              "vop"
            ]
          },
          "alternatives": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Alternative sets of required field paths: the recipient is complete when every path of at least one set is present (e.g. `[[\"bank.iban\"], [\"bank.accountNumber\", \"bank.routingCodes.sortCode\"]]`)."
          }
        },
        "required": [
          "currency",
          "bankCountry",
          "recipientType",
          "rails",
          "fields"
        ]
      },
      "RecipientStatus": {
        "type": "string",
        "enum": [
          "pending_review",
          "approved",
          "on_hold",
          "declined",
          "cancelled"
        ]
      },
      "RecipientType": {
        "type": "string",
        "enum": [
          "individual",
          "company"
        ]
      },
      "RecipientUpdate": {
        "type": "object",
        "description": "Changing `bank` or `name` re-triggers verification and approval (FR-REC-05).",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "nickname": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          },
          "email": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Email"
              },
              {
                "type": "null"
              }
            ]
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "bank": {
            "$ref": "#/components/schemas/RecipientBank"
          },
          "defaultReference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 35
          },
          "purpose": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          },
          "metadata": {
            "$ref": "#/components/schemas/MetadataPatch"
          }
        },
        "additionalProperties": false
      },
      "RecipientVerification": {
        "type": "object",
        "properties": {
          "scheme": {
            "type": "string",
            "enum": [
              "cop",
              "vop"
            ]
          },
          "outcome": {
            "$ref": "#/components/schemas/VerificationOutcome"
          },
          "matchedName": {
            "type": [
              "string",
              "null"
            ]
          },
          "reasonCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "verifiedAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "overriddenBy": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "overrideReason": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "scheme",
          "outcome",
          "provider",
          "verifiedAt"
        ]
      },
      "RiskRating": {
        "type": "string",
        "enum": [
          "low",
          "medium",
          "high",
          "severe"
        ]
      },
      "SandboxConnectionConfig": {
        "type": "object",
        "properties": {
          "quoteTtlSeconds": {
            "default": 30,
            "type": "integer",
            "minimum": 5,
            "maximum": 3600
          },
          "rateShiftsBps": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "pattern": "^[A-Z]{3}\\/[A-Z]{3}$"
            },
            "additionalProperties": {
              "type": "integer",
              "minimum": -5000,
              "maximum": 5000
            }
          },
          "outageUntil": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
              },
              {
                "type": "null"
              }
            ]
          },
          "materialiseUnknown": {
            "default": false,
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Sandbox (simulated bank) connection configuration (non-secret; from the adapter schema in `@wirebloom/providers`)."
      },
      "SandboxIncomingPayment": {
        "type": "object",
        "properties": {
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "senderName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "reference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          }
        },
        "required": [
          "balanceId",
          "amount"
        ],
        "additionalProperties": false
      },
      "SandboxPaymentStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "completed",
              "rejected",
              "cancelled",
              "returned"
            ]
          }
        },
        "required": [
          "status"
        ],
        "additionalProperties": false
      },
      "SandboxReset": {
        "type": "object",
        "properties": {
          "deliveriesDeleted": {
            "type": "integer",
            "minimum": 0
          },
          "endpointsReactivated": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "deliveriesDeleted",
          "endpointsReactivated"
        ]
      },
      "SandboxSimulation": {
        "type": "object",
        "properties": {
          "simulationId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued"
            ]
          },
          "endpoints": {
            "type": "integer",
            "minimum": 0
          },
          "objectId": {
            "$ref": "#/components/schemas/Uuid"
          }
        },
        "required": [
          "simulationId",
          "status"
        ]
      },
      "SandboxWebhookEvent": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/IntegratorEventType"
          },
          "objectId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "status": {
            "type": "string",
            "minLength": 1,
            "maxLength": 40
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "type"
        ],
        "additionalProperties": false
      },
      "SchedulePreview": {
        "type": "object",
        "properties": {
          "rrule": {
            "type": "string",
            "description": "Canonical RRULE."
          },
          "runs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlannedRun"
            }
          }
        },
        "required": [
          "rrule",
          "runs"
        ]
      },
      "SchedulePreviewRequest": {
        "type": "object",
        "properties": {
          "schedule": {
            "type": "object",
            "properties": {
              "rrule": {
                "type": "string"
              },
              "startDate": {
                "$ref": "#/components/schemas/Date"
              },
              "endDate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "timezone": {
                "type": "string"
              }
            },
            "required": [
              "rrule",
              "startDate"
            ]
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "rail": {
            "$ref": "#/components/schemas/Rail"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 60,
            "default": 12
          }
        },
        "required": [
          "schedule",
          "currency"
        ],
        "additionalProperties": false
      },
      "ScheduledOccurrence": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "occurrenceDate": {
            "$ref": "#/components/schemas/Date"
          },
          "executionDate": {
            "$ref": "#/components/schemas/Date"
          },
          "status": {
            "type": "string",
            "enum": [
              "created",
              "completed",
              "failed",
              "skipped"
            ]
          },
          "paymentId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "collectionId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "failureReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "occurrenceDate",
          "executionDate",
          "status",
          "createdAt"
        ]
      },
      "ScheduledOccurrences": {
        "type": "object",
        "properties": {
          "upcoming": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlannedRun"
            }
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScheduledOccurrence"
            }
          }
        },
        "required": [
          "upcoming",
          "history"
        ]
      },
      "ScheduledPayment": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100
          },
          "template": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ScheduledPaymentTemplate"
              },
              {
                "$ref": "#/components/schemas/CollectionScheduleTemplate"
              }
            ]
          },
          "schedule": {
            "type": "object",
            "properties": {
              "rrule": {
                "type": "string",
                "description": "RFC 5545 RRULE.",
                "examples": [
                  "FREQ=MONTHLY;BYMONTHDAY=1"
                ]
              },
              "startDate": {
                "$ref": "#/components/schemas/Date"
              },
              "endDate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "timezone": {
                "type": "string",
                "examples": [
                  "Europe/London"
                ]
              }
            },
            "required": [
              "rrule",
              "startDate"
            ]
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ScheduledPaymentStatus"
              }
            ],
            "readOnly": true
          },
          "nextRunAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "lastPaymentId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "updatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "payment",
              "collection"
            ],
            "readOnly": true
          },
          "nextExecutionDate": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "consecutiveFailures": {
            "type": "integer",
            "description": "Failed runs in a row; three deactivate the schedule.",
            "minimum": 0,
            "readOnly": true
          },
          "preApproved": {
            "type": "boolean",
            "description": "Runs skip the approval tier (operator setting `payments.scheduled.preApproveStandingOrders`, approved at creation).",
            "readOnly": true
          },
          "statusReason": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "customerId",
          "template",
          "schedule",
          "status",
          "createdAt"
        ]
      },
      "ScheduledPaymentPage": {
        "type": "object",
        "description": "Cursor-paginated list of ScheduledPayment.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScheduledPayment"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "ScheduledPaymentStatus": {
        "type": "string",
        "enum": [
          "active",
          "inactive",
          "ended"
        ]
      },
      "ScheduledPaymentTemplate": {
        "type": "object",
        "description": "Standing order / scheduled payment template.",
        "properties": {
          "sourceBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "recipientId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "reference": {
            "type": "string",
            "maxLength": 140
          },
          "purposeCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientName": {
            "type": [
              "string",
              "null"
            ],
            "description": "The recipient's name (responses only; null when the recipient no longer exists).",
            "readOnly": true
          }
        },
        "required": [
          "sourceBalanceId",
          "recipientId",
          "amount",
          "reference"
        ]
      },
      "ScheduledPaymentWrite": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100
          },
          "template": {
            "type": "object",
            "properties": {
              "sourceBalanceId": {
                "$ref": "#/components/schemas/Uuid"
              },
              "recipientId": {
                "$ref": "#/components/schemas/Uuid"
              },
              "amount": {
                "$ref": "#/components/schemas/PositiveMoney"
              },
              "reference": {
                "type": "string",
                "maxLength": 140
              },
              "purposeCode": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "sourceBalanceId",
              "recipientId",
              "amount",
              "reference"
            ]
          },
          "schedule": {
            "type": "object",
            "properties": {
              "rrule": {
                "type": "string"
              },
              "startDate": {
                "$ref": "#/components/schemas/Date"
              },
              "endDate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "timezone": {
                "type": "string"
              }
            },
            "required": [
              "rrule",
              "startDate"
            ]
          }
        },
        "required": [
          "template",
          "schedule"
        ],
        "additionalProperties": false
      },
      "SimCardTransaction": {
        "type": "object",
        "properties": {
          "phase": {
            "type": "string",
            "enum": [
              "authorisation",
              "decline",
              "reversal",
              "settlement",
              "refund"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "ref": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_.:-]{3,100}$",
            "description": "Transaction ref (generated for an authorisation; required to reverse or settle one)."
          },
          "relatedRef": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_.:-]{3,100}$",
            "description": "Refund: the settled transaction it refunds."
          },
          "merchantName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "mcc": {
            "type": "string",
            "pattern": "^\\d{4}$"
          },
          "merchantCountry": {
            "$ref": "#/components/schemas/CountryCode"
          },
          "channel": {
            "type": "string",
            "enum": [
              "pos",
              "contactless",
              "ecommerce",
              "atm",
              "moto"
            ]
          },
          "declineReason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "phase",
          "amount"
        ],
        "additionalProperties": false
      },
      "SimCollectionStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "collected",
              "failed",
              "returned"
            ]
          },
          "reasonCode": {
            "type": "string",
            "pattern": "^[A-Z0-9]{2,8}$"
          }
        },
        "required": [
          "status"
        ],
        "additionalProperties": false
      },
      "SimExchangeStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "failed"
            ]
          }
        },
        "required": [
          "status"
        ],
        "additionalProperties": false
      },
      "SimFxRate": {
        "type": "object",
        "properties": {
          "sell": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "buy": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "moveBps": {
            "type": "integer",
            "description": "Basis points, ±5000; `0` resets the pair.",
            "minimum": -5000,
            "maximum": 5000
          }
        },
        "required": [
          "sell",
          "buy",
          "moveBps"
        ],
        "additionalProperties": false
      },
      "SimIncomingDebit": {
        "type": "object",
        "properties": {
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "scheme": {
            "type": "string",
            "enum": [
              "SEPA_DD",
              "BACS_DD",
              "NPP"
            ]
          },
          "valueDate": {
            "$ref": "#/components/schemas/Date"
          }
        },
        "required": [
          "balanceId",
          "amount"
        ],
        "additionalProperties": false
      },
      "SimIncomingPayment": {
        "type": "object",
        "properties": {
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "senderName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "reference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "scheme": {
            "type": "string",
            "description": "Partner scheme (Banking Circle `SEPA`, `SEPAINST`, `FPS`, `NPP`; Integrated Finance `sepa`, …); by currency when absent.",
            "pattern": "^[A-Z_]{2,12}$"
          }
        },
        "required": [
          "balanceId",
          "amount"
        ],
        "additionalProperties": false
      },
      "SimIncomingRecall": {
        "type": "object",
        "properties": {
          "reasonCode": {
            "type": "string",
            "enum": [
              "AC03",
              "AM09",
              "DUPL",
              "DT01",
              "FRAD",
              "CUST",
              "TECH",
              "UNKF",
              "MS01"
            ]
          }
        },
        "required": [
          "reasonCode"
        ],
        "additionalProperties": false
      },
      "SimKycOutcome": {
        "type": "object",
        "properties": {
          "personId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "approved",
              "rejected",
              "retry"
            ]
          },
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        },
        "required": [
          "personId",
          "outcome"
        ],
        "additionalProperties": false
      },
      "SimOutage": {
        "type": "object",
        "properties": {
          "durationSeconds": {
            "type": "integer",
            "description": "Seconds from now; `0` ends the outage.",
            "minimum": 0,
            "maximum": 900
          }
        },
        "required": [
          "durationSeconds"
        ],
        "additionalProperties": false
      },
      "SimPaymentRecall": {
        "type": "object",
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "accepted",
              "rejected"
            ]
          },
          "reasonCode": {
            "type": "string",
            "pattern": "^[A-Z0-9]{2,8}$"
          }
        },
        "required": [
          "outcome"
        ],
        "additionalProperties": false
      },
      "SimPaymentReturn": {
        "type": "object",
        "description": "Partial return with `amount`; the payment amount otherwise.",
        "properties": {
          "reasonCode": {
            "type": "string",
            "pattern": "^[A-Z0-9]{2,8}$"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "additionalProperties": false
      },
      "SimPaymentStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "completed",
              "rejected",
              "cancelled"
            ]
          },
          "failureReason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          }
        },
        "required": [
          "status"
        ],
        "additionalProperties": false
      },
      "SimStatement": {
        "type": "object",
        "properties": {
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "periodStart": {
            "$ref": "#/components/schemas/Date"
          },
          "periodEnd": {
            "$ref": "#/components/schemas/Date"
          }
        },
        "required": [
          "balanceId"
        ],
        "additionalProperties": false
      },
      "SimWebhookEvent": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/IntegratorEventType"
          },
          "objectId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "status": {
            "type": "string",
            "minLength": 1,
            "maxLength": 40
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "type"
        ],
        "additionalProperties": false
      },
      "SimulationCatalogue": {
        "type": "object",
        "properties": {
          "environment": {
            "type": "string",
            "enum": [
              "sandbox"
            ]
          },
          "connection": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "provider": {
                "type": "string"
              },
              "environment": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "provider",
              "environment"
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "$ref": "#/components/schemas/SimulationKind"
                },
                "method": {
                  "type": "string",
                  "enum": [
                    "POST"
                  ]
                },
                "path": {
                  "type": "string"
                },
                "summary": {
                  "type": "string"
                },
                "providers": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SimulationProvider"
                  }
                },
                "available": {
                  "type": "boolean",
                  "description": "Available for the caller's connection."
                },
                "rules": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "kind",
                "method",
                "path",
                "summary",
                "providers",
                "available",
                "rules"
              ]
            }
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "topic": {
                  "type": "string"
                },
                "rule": {
                  "type": "string"
                }
              },
              "required": [
                "topic",
                "rule"
              ]
            },
            "description": "Deterministic sandbox rules that need no endpoint."
          }
        },
        "required": [
          "environment",
          "connection",
          "data",
          "rules"
        ]
      },
      "SimulationKind": {
        "type": "string",
        "enum": [
          "incoming_payment",
          "incoming_debit",
          "payment_status",
          "payment_return",
          "payment_recall",
          "incoming_recall",
          "exchange_status",
          "fx_rate_move",
          "collection_status",
          "card_transaction",
          "kyc_outcome",
          "webhook_event",
          "statement",
          "scheduled_run",
          "provider_outage"
        ]
      },
      "SimulationProvider": {
        "type": "string",
        "enum": [
          "sandbox",
          "banking_circle",
          "integrated_finance"
        ]
      },
      "SimulationResult": {
        "type": "object",
        "properties": {
          "simulationId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "kind": {
            "$ref": "#/components/schemas/SimulationKind"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "submitted",
              "applied"
            ],
            "description": "`queued`: a provider event was stored and handed to the workers; `submitted`: the partner sandbox accepted it and notifies by webhook; `applied`: done synchronously."
          },
          "provider": {
            "$ref": "#/components/schemas/SimulationProvider"
          },
          "providerEventIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            },
            "description": "`providers.events` rows written (provider event log)."
          },
          "providerReference": {
            "type": [
              "string",
              "null"
            ]
          },
          "details": {
            "type": "object",
            "description": "Per kind (amounts, refs, rates, case id, …).",
            "properties": {},
            "additionalProperties": true
          }
        },
        "required": [
          "simulationId",
          "kind",
          "status",
          "provider",
          "providerEventIds",
          "providerReference",
          "details"
        ]
      },
      "Statement": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "periodStart": {
            "$ref": "#/components/schemas/Date"
          },
          "periodEnd": {
            "$ref": "#/components/schemas/Date"
          },
          "opening": {
            "$ref": "#/components/schemas/Money"
          },
          "closing": {
            "$ref": "#/components/schemas/Money"
          },
          "formats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExportFormat"
            }
          },
          "generatedAt": {
            "$ref": "#/components/schemas/Timestamp"
          }
        },
        "required": [
          "id",
          "balanceId",
          "periodStart",
          "periodEnd",
          "opening",
          "closing",
          "formats",
          "generatedAt"
        ]
      },
      "StatementPage": {
        "type": "object",
        "description": "Cursor-paginated list of Statement.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Statement"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "StatementRequest": {
        "type": "object",
        "description": "Ad-hoc statement for a custom period (asynchronous).",
        "properties": {
          "periodStart": {
            "$ref": "#/components/schemas/Date"
          },
          "periodEnd": {
            "$ref": "#/components/schemas/Date"
          },
          "format": {
            "$ref": "#/components/schemas/ExportFormat"
          }
        },
        "required": [
          "periodStart",
          "periodEnd",
          "format"
        ],
        "additionalProperties": false
      },
      "StepUpAction": {
        "type": "string",
        "enum": [
          "people.invite",
          "people.change_role",
          "primary_owner.transfer",
          "recipient.create",
          "recipient.update",
          "payment.first_to_recipient",
          "payment.above_threshold",
          "provider_connection.change",
          "api_key.create",
          "mfa.change",
          "statement.full_export",
          "impersonation.start",
          "customer.closure",
          "staff.mfa_reset",
          "manual_posting.approve",
          "batch_rail.import",
          "ops.payment_action",
          "ops.kyb_decision",
          "ops.recipient_decision",
          "ops.exception_resolve",
          "ops.alert_resolve",
          "accounting_connection.change",
          "ops.closure_decision",
          "ops.four_eyes_decision",
          "ops.data_request_export",
          "ops.data_request_erasure",
          "treasury.approve",
          "cases.recall_decision",
          "compliance.hold_decision",
          "compliance.screening_decision",
          "compliance.suppression",
          "compliance.edd_decision",
          "mlro.sign_off",
          "mlro.designation",
          "api_key.revoke",
          "integrator_webhook.change",
          "viban.pool_change",
          "viban.lifecycle",
          "partner_assets.change",
          "resolution_pack.download",
          "regulatory_pack.download",
          "platform.status_change",
          "developer_programme.change",
          "regulatory_pack.generate",
          "compliance.gate_settings_change",
          "platform.change",
          "provider_costs.change",
          "ops.policy_change",
          "status.change",
          "resolution_pack.generate",
          "safeguarding.sign_off"
        ],
        "description": "Actions that require a fresh MFA/passkey assertion (SECURITY.md §1.2, FR-AUTH-03)."
      },
      "Timestamp": {
        "type": "string",
        "description": "RFC 3339 timestamp in UTC (suffix `Z`).",
        "format": "date-time",
        "examples": [
          "2026-09-23T10:15:30Z"
        ]
      },
      "Transaction": {
        "type": "object",
        "description": "A customer-visible transaction (one journal entry projected onto the customer's balance). `amount` is signed (negative = debit). `secondaryAmount` shows the other leg of an FX transaction.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true,
            "description": "Journal entry id."
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "kind": {
            "$ref": "#/components/schemas/JournalEntryKind"
          },
          "type": {
            "$ref": "#/components/schemas/TransactionType"
          },
          "status": {
            "$ref": "#/components/schemas/TransactionStatus"
          },
          "description": {
            "type": "string",
            "examples": [
              "Payment to Acme GmbH"
            ]
          },
          "counterpartyName": {
            "type": [
              "string",
              "null"
            ]
          },
          "balanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "balanceName": {
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "secondaryAmount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "fee": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "orderId": {
            "type": [
              "string",
              "null"
            ]
          },
          "subject": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "payment",
                  "incoming_payment",
                  "transfer",
                  "exchange",
                  "billing_item",
                  "card_transaction",
                  "collection",
                  "adjustment"
                ]
              },
              "id": {
                "$ref": "#/components/schemas/Uuid"
              }
            },
            "required": [
              "type",
              "id"
            ]
          },
          "postedAt": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "valueDate": {
            "$ref": "#/components/schemas/Date"
          },
          "attachmentCount": {
            "type": "integer",
            "minimum": 0
          },
          "annotationCount": {
            "type": "integer",
            "minimum": 0
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "runningBalance": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "customerId",
          "kind",
          "type",
          "status",
          "description",
          "balanceId",
          "amount",
          "postedAt",
          "valueDate",
          "attachmentCount",
          "annotationCount"
        ],
        "examples": [
          {
            "id": "0192a6f2-0000-7000-8000-00000000e001",
            "customerId": "0192a6f0-0000-7000-8000-0000000000c1",
            "kind": "payment",
            "type": "payment",
            "status": "completed",
            "description": "Payment to Acme GmbH",
            "counterpartyName": "Acme GmbH",
            "balanceId": "0192a6f1-1111-7000-8000-00000000b001",
            "balanceName": "GBP Main",
            "amount": {
              "amountMinor": "-85630",
              "currency": "GBP"
            },
            "secondaryAmount": {
              "amountMinor": "100000",
              "currency": "EUR"
            },
            "fee": {
              "amountMinor": "150",
              "currency": "GBP"
            },
            "reference": "INV-2026-0042",
            "orderId": "P7KX2M9QD1AB",
            "postedAt": "2026-09-23T11:02:00Z",
            "valueDate": "2026-09-23",
            "attachmentCount": 1,
            "annotationCount": 0,
            "labels": []
          }
        ]
      },
      "TransactionDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Transaction"
          },
          {
            "type": "object",
            "properties": {
              "sender": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "maskedIdentifier": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "bankCountry": {
                    "anyOf": [
                      {
                        "$ref": "#/components/schemas/CountryCode"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              },
              "remittanceInfo": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "totalExcludingFees": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "rate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Rate"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "updates": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PaymentEvent"
                }
              },
              "confirmationAvailable": {
                "type": "boolean"
              },
              "note": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Customer note set with `PATCH /transactions/{transactionId}`."
              }
            }
          }
        ]
      },
      "TransactionExportFilter": {
        "type": "object",
        "description": "`ExportRequest.filter`: the `GET /transactions` filters with their types (booleans, enums, dates, amounts); the period comes from `from`/`to`.",
        "properties": {
          "dateFrom": {
            "type": "string",
            "description": "Narrows the export period (`from`/`to` still apply).",
            "format": "date"
          },
          "dateTo": {
            "type": "string",
            "format": "date"
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TransactionStatus"
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TransactionStatus"
                },
                "minItems": 1
              }
            ],
            "description": "TransactionStatus. One value or an array (OR); a comma-separated string is also accepted."
          },
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TransactionType"
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TransactionType"
                },
                "minItems": 1
              }
            ],
            "description": "TransactionType. One value or an array (OR); a comma-separated string is also accepted."
          },
          "balanceId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "minItems": 1
              }
            ],
            "description": "Balance ids (intersected with `balanceIds`). One value or an array (OR); a comma-separated string is also accepted."
          },
          "currency": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CurrencyCode"
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CurrencyCode"
                },
                "minItems": 1
              }
            ],
            "description": "Currencies. One value or an array (OR); a comma-separated string is also accepted."
          },
          "hasAttachments": {
            "type": "boolean"
          },
          "hasAnnotations": {
            "type": "boolean"
          },
          "label": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 50
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 50
                },
                "minItems": 1
              }
            ],
            "description": "Labels. One value or an array (OR); a comma-separated string is also accepted."
          },
          "amountMin": {
            "$ref": "#/components/schemas/AmountMinor"
          },
          "amountMax": {
            "$ref": "#/components/schemas/AmountMinor"
          },
          "direction": {
            "type": "string",
            "enum": [
              "in",
              "out"
            ]
          },
          "counterparty": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "q": {
            "type": "string",
            "description": "Free-text search, as `q` on `GET /transactions`.",
            "minLength": 2,
            "maxLength": 200
          }
        },
        "additionalProperties": false
      },
      "TransactionPage": {
        "type": "object",
        "description": "Cursor-paginated list of Transaction.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transaction"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "TransactionStatus": {
        "type": "string",
        "enum": [
          "pending",
          "completed",
          "failed",
          "returned",
          "cancelled",
          "on_hold",
          "funds_required"
        ],
        "description": "Customer-facing status of a ledger transaction, derived from the subject (payment, incoming payment, exchange, billing item). ASSUMPTION: not a stored enum in DATABASE.md."
      },
      "TransactionType": {
        "type": "string",
        "enum": [
          "credit",
          "payment",
          "transfer",
          "exchange",
          "fee",
          "card",
          "interest",
          "adjustment"
        ],
        "description": "Display type used by the Transactions filter (Equals: Credit, Payment, Exchange, Fee). Derived from JournalEntryKind."
      },
      "Transfer": {
        "type": "object",
        "description": "Internal transfer between own balances of the same currency (payment `kind=internal`, ledger-only).",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "customerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "fromBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "toBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentStatus"
              }
            ],
            "readOnly": true
          },
          "createdBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          },
          "completedAt": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Timestamp"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          },
          "transactionId": {
            "anyOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "readOnly": true
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "customerId",
          "fromBalanceId",
          "toBalanceId",
          "amount",
          "status",
          "createdAt"
        ]
      },
      "TransferCreate": {
        "type": "object",
        "properties": {
          "fromBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "toBalanceId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveMoney"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          }
        },
        "required": [
          "fromBalanceId",
          "toBalanceId",
          "amount"
        ],
        "additionalProperties": false,
        "examples": [
          {
            "fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
            "toBalanceId": "0192a6f1-1111-7000-8000-00000000b002",
            "amount": {
              "amountMinor": "50000",
              "currency": "GBP"
            },
            "reference": "Payroll top-up"
          }
        ]
      },
      "TransferPage": {
        "type": "object",
        "description": "Cursor-paginated list of Transfer.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transfer"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "Uuid": {
        "type": "string",
        "description": "UUID (v4 or v7). All resource ids are UUIDs.",
        "format": "uuid",
        "examples": [
          "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
        ]
      },
      "VerificationOutcome": {
        "type": "string",
        "enum": [
          "match",
          "close_match",
          "no_match",
          "not_available",
          "unavailable_error"
        ],
        "description": "Confirmation of Payee (UK) / Verification of Payee (SEPA) outcome. ASSUMPTION: values derived from FR-REC-02."
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "readOnly": true
          },
          "eventId": {
            "$ref": "#/components/schemas/Uuid"
          },
          "eventType": {
            "$ref": "#/components/schemas/IntegratorEventType"
          },
          "attempt": {
            "type": "integer",
            "minimum": 1
          },
          "statusCode": {
            "type": [
              "integer",
              "null"
            ]
          },
          "durationMs": {
            "type": [
              "integer",
              "null"
            ]
          },
          "succeeded": {
            "type": "boolean"
          },
          "nextRetryAt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "id",
          "eventId",
          "eventType",
          "attempt",
          "succeeded",
          "createdAt"
        ]
      },
      "WebhookDeliveryPage": {
        "type": "object",
        "description": "Cursor-paginated list of WebhookDelivery.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        },
        "required": [
          "data",
          "page"
        ]
      },
      "WebhookPartnerState": {
        "type": "string",
        "enum": [
          "unregistered",
          "requested",
          "confirmed"
        ],
        "description": "Integrated Finance registration detail: `requested` once the pack was sent, `confirmed` on the first verified event through the current URL. `null` for Banking Circle."
      },
      "WebhookRegistrationState": {
        "type": "string",
        "enum": [
          "pending",
          "registered",
          "failed"
        ],
        "description": "`providers.connections.webhook_registration_state`, read by the activation checklist (P5-T07): `pending` until the partner delivers or confirms, `registered` when Banking Circle subscriptions are active or Integrated Finance confirmed (acknowledged or first verified event), `failed` when the last registration failed or Banking Circle deactivated the subscription."
      }
    },
    "parameters": {
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 512
        },
        "description": "Opaque cursor from `page.nextCursor` or `page.prevCursor`. Must be used with the same `sort` and `filter` as the request that produced it (`400 invalid-cursor` otherwise)."
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255,
          "pattern": "^[A-Za-z0-9._:-]+$",
          "examples": [
            "7f9c2e3a-4b1d-4e8f-9a2b-6c5d4e3f2a1b"
          ]
        },
        "description": "Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with `Idempotency-Replayed: true`. Same key + different body → `422 idempotency-key-reused`. Concurrent request with a key still in progress → `409 idempotency-key-in-use` + `Retry-After`. 5xx, 401, 403 (incl. `step-up-required`) and 429 responses are not stored: the key is released, so the retry (after re-authentication, step-up or back-off) may use the same key."
      },
      "IdempotencyKeyOptional": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255,
          "pattern": "^[A-Za-z0-9._:-]+$"
        },
        "description": "Optional idempotency key; same semantics as on money operations."
      },
      "IfMatch": {
        "name": "If-Match",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "examples": [
            "\"W/\\\"3\\\"\""
          ]
        },
        "description": "ETag of the representation being modified (from a prior GET/PATCH)."
      },
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Conditional GET; `304` when unchanged."
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        },
        "description": "Page size (max 100)."
      },
      "RequestId": {
        "name": "X-Request-Id",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._:-]{8,128}$",
          "examples": [
            "req_01J8Z6Q7R2"
          ]
        },
        "description": "Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details."
      },
      "TenantId": {
        "name": "X-Tenant-Id",
        "in": "header",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → `403`. For API keys it must equal the key's customer id (customer-level keys are bound to one customer) or, for operator-level keys (P9-T08b), the operator id."
      }
    },
    "headers": {
      "ETag": {
        "description": "Entity tag of the returned representation (weak ETag of the row version). Send as `If-Match` on updates.",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyReplayed": {
        "description": "`true` when the response is a replay of a stored idempotent response.",
        "schema": {
          "type": "boolean"
        }
      },
      "Location": {
        "description": "URL of the created resource or job.",
        "schema": {
          "type": "string",
          "format": "uri-reference"
        }
      },
      "RateLimitLimit": {
        "description": "Request quota in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Remaining requests in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Seconds until the window resets.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "WWWAuthenticate": {
        "description": "Authentication challenge (`Bearer realm=\"wirebloom\"` for bearer/API key).",
        "schema": {
          "type": "string"
        }
      },
      "XRequestId": {
        "description": "Request correlation id (echo or server-generated).",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "bad-request": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/bad-request",
                  "title": "Bad request",
                  "status": 400,
                  "detail": "Bad request.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "bad_request",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "Conflict": {
        "description": "State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "invalid-transition": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/invalid-transition",
                  "title": "Invalid state transition",
                  "status": 409,
                  "detail": "Invalid state transition.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "invalid_transition",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "Error": {
        "description": "Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "internal-error": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/internal-error",
                  "title": "Internal error",
                  "status": 500,
                  "detail": "Internal error.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "internal_error",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "forbidden": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/forbidden",
                  "title": "Forbidden",
                  "status": 403,
                  "detail": "Forbidden.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "forbidden",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "not-found": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/not-found",
                  "title": "Not found",
                  "status": 404,
                  "detail": "Not found.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "not_found",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "NotModified": {
        "description": "Not modified (`If-None-Match` matched).",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          },
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        }
      },
      "PreconditionFailed": {
        "description": "`If-Match` does not match the current ETag (resource changed).",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "precondition-failed": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/precondition-failed",
                  "title": "Precondition failed",
                  "status": 412,
                  "detail": "Precondition failed.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "precondition_failed",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "PreconditionRequired": {
        "description": "`If-Match` header is required for this operation.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "precondition-required": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/precondition-required",
                  "title": "Precondition required",
                  "status": 428,
                  "detail": "Precondition required.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "precondition_required",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "rate-limited": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/rate-limited",
                  "title": "Too many requests",
                  "status": 429,
                  "detail": "Too many requests.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "rate_limited",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WWWAuthenticate"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "unauthenticated": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/unauthenticated",
                  "title": "Authentication required",
                  "status": 401,
                  "detail": "Authentication required.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "unauthenticated",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      },
      "UnprocessableContent": {
        "description": "Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "validation-error": {
                "value": {
                  "type": "https://api.banking.wirebloom.com/problems/validation-error",
                  "title": "Validation failed",
                  "status": 422,
                  "detail": "Validation failed.",
                  "instance": "/v1/payments#req_01J8Z6Q7R2",
                  "code": "validation_error",
                  "requestId": "req_01J8Z6Q7R2"
                }
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "wb_live_* | wb_test_*",
        "description": "Integrators: `Authorization: Bearer wb_live_...` (or `wb_test_...` for the sandbox tenant). Customer-level keys belong to one customer; operator-level keys (P9-T08b) belong to the operator and act only with `X-Tenant-Id` = the operator id. Keys carry scopes, optional IP allow-list and expiry; hashed at rest; shown once. Customer scopes: `balances:read`, `transactions:read`, `statements:read`, `recipients:read`, `recipients:write`, `payments:read`, `payments:write`, `exchanges:read`, `exchanges:write`, `webhooks:manage`. Operator scopes: `customers:read`, `customers:write`, `onboarding:read`, `treasury:read`, `reports:read`, `integration:read`, `webhooks:manage`. An operator key calling a customer-only operation gets `403 insufficient-scope`. Operations list the required scope in the security requirement and in `x-api-key-scopes`. Operations without an `apiKey` requirement are not available to API keys. API-key money operations are subject to the same approval tiers and limits as the UI (D-24) and cannot approve."
      }
    }
  }
}
