{
  "openapi": "3.0.3",
  "info": {
    "title": "Moneybook API",
    "version": "0.1.0",
    "description": "API contract for Moneybook personal finance platform.\n\nProduction availability: Wealth APIs are implemented in development; their\nseparate production rollout is pending.\n\nImport filenames must be basenames without separators, traversal segments or control\ncharacters; invalid names return 400 IMPORT_INVALID_FILENAME.\n\nResource limits: multipart files are limited to 10 MiB each and requests to 20 MiB\n(SOR documents retain their stricter 5 MiB domain limit). Oversized multipart\nrequests return 413 with UPLOAD_TOO_LARGE (SOR routes use SOR_DOCUMENT_TOO_LARGE). Authenticated /v1 requests have an\ninstance-local fixed-window limit, default 120/minute per verified identity;\nexcess requests return 429 with RATE_LIMITED and Retry-After seconds. Health\nprobes and the separately authenticated scheduler route are excluded.\n\nUnexpected server failures return INTERNAL_ERROR with a generic message; internal\nexception details, database queries, paths and credentials are never returned.\n\nAuthentication: every operation except health needs either a Supabase Auth access token\n(`Authorization: Bearer <jwt>`, verified against the project's JWKS, issuer\n`<SUPABASE_URL>/auth/v1`, audience `authenticated`) or a Moneybook API key\n(`X-Spective-Api-Key`). Client-supplied identity headers are ignored.\n\nWorkspaces: data is owned by a workspace. Workspace-scoped operations act on the workspace\nnamed by the `X-Spective-Workspace-Id` header (or the `workspaceId` path parameter) and\ndefault to the caller's personal workspace. The caller must be an active member; a workspace\nthe caller cannot see answers 404 `WORKSPACE_NOT_FOUND`, a role without the needed\npermission answers 403 `WORKSPACE_ACCESS_DENIED`. Roles: OWNER (everything, manages\nmembers), EDITOR (read, write), AUDITOR (read, export, audit trail),\nVIEWER (read). GET operations need READ, other methods need WRITE unless stated. API keys\nare pinned to the workspace they were created in.\n"
  },
  "servers": [
    {
      "url": "http://localhost:8080",
      "description": "Local development"
    },
    {
      "url": "https://spective-backend-1053388195102.asia-south1.run.app",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/internal/jobs/dispatch": {
      "post": {
        "tags": [
          "Jobs"
        ],
        "operationId": "dispatchScheduledDurableJob",
        "description": "Disabled by default. Requires Google-signed OIDC token from the exact configured scheduler service account, exact audience, verified email and Google issuer. Supabase tokens and API keys are rejected. Claims at most one durable job with the same outcomes as administrator dispatch.",
        "responses": {
          "200": {
            "description": "Bounded durable dispatch outcome"
          },
          "401": {
            "description": "Valid scheduler identity token required"
          },
          "403": {
            "description": "Scheduler identity required"
          },
          "404": {
            "description": "Scheduler dispatch disabled"
          }
        }
      }
    },
    "/v1/admin/jobs/dispatch": {
      "post": {
        "tags": [
          "Jobs"
        ],
        "operationId": "dispatchDurableJobs",
        "description": "ADMIN bearer-only bounded dispatch of at most one durable job. Disabled unless durable mode and dispatch are enabled. Claims are atomic; repeated requests cannot execute an already claimed job. Expired claims become UNCERTAIN and require operator reconciliation, never automatic replay of financial or notification effects.",
        "responses": {
          "200": {
            "description": "Dispatch outcome, containing no job payload or exception details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "IDLE",
                        "SUCCEEDED",
                        "FAILED",
                        "UNCERTAIN"
                      ]
                    },
                    "jobId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "Platform ADMIN bearer token required"
          },
          "404": {
            "description": "Durable dispatch disabled"
          }
        }
      }
    },
    "/v1/sor/statements": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "stageSorStatement",
        "description": "Persist immutable statement extraction; verify source ownership, arithmetic and running balances. No ledger writes yet.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorStatement"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorStatementRequest"
              }
            }
          }
        }
      }
    },
    "/v1/sor/statements/{id}": {
      "get": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "getSorStatement",
        "description": "Feature-flagged owner-scoped SOR operation. Requires sor:read or sor:write as appropriate.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorStatement"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ]
      }
    },
    "/v1/sor/statements/{id}/commit": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "commitSorStatement",
        "description": "Atomic ledger/provenance/audit commit. Reject stale ledger, overlapping periods and opening mismatch. No guessed opening adjustment or external jobs.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorStatement"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorStatementCommit"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ]
      }
    },
    "/v1/sor/statements/{id}/discard": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "discardSorStatement",
        "description": "Feature-flagged owner-scoped SOR operation. Requires sor:read or sor:write as appropriate.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorStatement"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ]
      }
    },
    "/v1/sor/positions": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "createSorPosition",
        "description": "Create immutable owned asset/liability evidence; no guessed inventory or ownership. Same key/payload replays.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorPosition"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorPositionRequest"
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "listSorPositions",
        "description": "Bounded owner-scoped immutable inventory; cursor is the last returned ID. Requires sor:read or sor:write.",
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Inventory page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorPositionPage"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sor/positions/{id}": {
      "get": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "getSorPosition",
        "description": "Feature-flagged owner-scoped SOR operation. Requires sor:read or sor:write as appropriate.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorPosition"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ]
      }
    },
    "/v1/sor/valuations": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "appendSorValuation",
        "description": "Append dated value evidence. Server records observation time; no provider fetch or FX assumption.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorValuation"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorValuationRequest"
              }
            }
          }
        }
      }
    },
    "/v1/sor/net-worth": {
      "get": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "getSorNetWorth",
        "description": "Feature-flagged owner-scoped SOR operation. Requires sor:read or sor:write as appropriate.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorNetWorth"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "parameters": [
          {
            "name": "asOf",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "knowledgeCutoff",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "maxAgeDays",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 3650
            }
          }
        ]
      }
    },
    "/v1/sor/allocations": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "allocateSorPayment",
        "description": "Link part of an existing payment/refund to committed bill evidence. Bounds both payment and bill capacity; never posts spend twice.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorAllocation"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorAllocationRequest"
              }
            }
          }
        }
      }
    },
    "/v1/sor/allocations/{id}/reverse": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "reverseSorAllocation",
        "description": "Feature-flagged owner-scoped SOR operation. Requires sor:read or sor:write as appropriate.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorAllocation"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ]
      }
    },
    "/v1/sor/bills/{id}/settlement": {
      "get": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "getSorSettlement",
        "description": "Feature-flagged owner-scoped SOR operation. Requires sor:read or sor:write as appropriate.",
        "responses": {
          "200": {
            "description": "Owner-scoped result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorSettlement"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Verified authentication required"
          },
          "403": {
            "description": "SOR scope required"
          },
          "404": {
            "description": "Not found in owner scope"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ]
      }
    },
    "/v1/sor/documents": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "uploadSorDocument",
        "description": "Experimental feature flag required. Stores up to 5 MiB locally in PostgreSQL; no external extraction.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Uploaded source identity and server-computed digest",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorDocument"
                }
              }
            }
          },
          "400": {
            "description": "Strict validation failed; no change committed"
          },
          "404": {
            "description": "Resource not found in owner scope or feature disabled"
          },
          "409": {
            "description": "Idempotency or optimistic state conflict"
          }
        }
      }
    },
    "/v1/sor/bills": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "stageSorBill",
        "description": "Validate and persist an immutable draft. Same owner/key/content replays; changed content conflicts. Does not create ledger spend.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorBillRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persisted draft or idempotent replay",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorBill"
                }
              }
            }
          },
          "400": {
            "description": "Strict validation failed; no change committed"
          },
          "404": {
            "description": "Resource not found in owner scope or feature disabled"
          },
          "409": {
            "description": "Idempotency or optimistic state conflict"
          }
        }
      }
    },
    "/v1/sor/bills/{id}": {
      "get": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "getSorBill",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owner-scoped bill and immutable extraction proposal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorBill"
                }
              }
            }
          },
          "400": {
            "description": "Strict validation failed; no change committed"
          },
          "404": {
            "description": "Resource not found in owner scope or feature disabled"
          },
          "409": {
            "description": "Idempotency or optimistic state conflict"
          }
        }
      }
    },
    "/v1/sor/bills/{id}/commit": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "commitSorBill",
        "description": "Confirm the immutable bill evidence and append an audit event atomically. Replays safely; never posts duplicate spending. Payment allocation is a future operation.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Committed bill",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorBill"
                }
              }
            }
          },
          "400": {
            "description": "Strict validation failed; no change committed"
          },
          "404": {
            "description": "Resource not found in owner scope or feature disabled"
          },
          "409": {
            "description": "Idempotency or optimistic state conflict"
          }
        }
      }
    },
    "/v1/sor/classifications": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "proposeSorClassification",
        "description": "Persist a semantic category proposal with original category and evidence. Does not apply it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SorClassificationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Owner-scoped proposal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorClassification"
                }
              }
            }
          },
          "400": {
            "description": "Strict validation failed; no change committed"
          },
          "404": {
            "description": "Resource not found in owner scope or feature disabled"
          },
          "409": {
            "description": "Idempotency or optimistic state conflict"
          }
        }
      }
    },
    "/v1/sor/classifications/{id}/{action}": {
      "post": {
        "tags": [
          "SystemOfRecord"
        ],
        "operationId": "decideSorClassification",
        "description": "Atomically accept or revert a semantic category assignment, preserving source and audit evidence. Conflicts if the current category changed. Explicitly accepted assignments take precedence over automatic enrichment; new proposals alone never replace them. Reassignment uses a new proposal with the current expectedCategory and explicit acceptance.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "action",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "accept",
                "revert"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Decision and preserved original category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SorClassification"
                }
              }
            }
          },
          "400": {
            "description": "Strict validation failed; no change committed"
          },
          "404": {
            "description": "Resource not found in owner scope or feature disabled"
          },
          "409": {
            "description": "Idempotency or optimistic state conflict"
          }
        }
      }
    },
    "/v1/wealth/positions": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "listWealthPosition",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WealthPosition"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": []
      },
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "createWealthPosition",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthPosition"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthPositionWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/positions/{id}": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthPosition",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthPosition"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Wealth"
        ],
        "operationId": "updateWealthPosition",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthPosition"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthPositionWrite"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Wealth"
        ],
        "operationId": "archiveWealthPosition",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "responses": {
          "204": {
            "description": "Archived; historical evidence retained"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Version mismatch"
          }
        }
      }
    },
    "/v1/wealth/compensation": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "listWealthCompensation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WealthCompensation"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": []
      },
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "createWealthCompensation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthCompensation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthCompensationWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/compensation/{id}": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthCompensation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthCompensation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Wealth"
        ],
        "operationId": "updateWealthCompensation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthCompensation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthCompensationWrite"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Wealth"
        ],
        "operationId": "archiveWealthCompensation",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "responses": {
          "204": {
            "description": "Archived; historical evidence retained"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Version mismatch"
          }
        }
      }
    },
    "/v1/wealth/events": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "listWealthEvent",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WealthEvent"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": []
      },
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "createWealthEvent",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthEvent"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthEventWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/events/{id}": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthEvent",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthEvent"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Wealth"
        ],
        "operationId": "updateWealthEvent",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthEvent"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthEventWrite"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Wealth"
        ],
        "operationId": "archiveWealthEvent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "responses": {
          "204": {
            "description": "Archived; historical evidence retained"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Version mismatch"
          }
        }
      }
    },
    "/v1/wealth/scenarios": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "listWealthScenario",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WealthScenario"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": []
      },
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "createWealthScenario",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthScenario"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthScenarioWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/scenarios/{id}": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthScenario",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthScenario"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Wealth"
        ],
        "operationId": "updateWealthScenario",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthScenario"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthScenarioWrite"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Wealth"
        ],
        "operationId": "archiveWealthScenario",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "responses": {
          "204": {
            "description": "Archived; historical evidence retained"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Version mismatch"
          }
        }
      }
    },
    "/v1/wealth/allocations": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "listWealthAllocation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WealthAllocation"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": []
      },
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "createWealthAllocation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthAllocation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthAllocationWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/allocations/{id}": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthAllocation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthAllocation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Wealth"
        ],
        "operationId": "updateWealthAllocation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthAllocation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthAllocationWrite"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Wealth"
        ],
        "operationId": "archiveWealthAllocation",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Expected resource version. Mutations append a revision; evidence is retained."
          }
        ],
        "responses": {
          "204": {
            "description": "Archived; historical evidence retained"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Version mismatch"
          }
        }
      }
    },
    "/v1/wealth/positions/{id}/valuations": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "listWealthValuations",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WealthValuation"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "appendWealthValuation",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthValuation"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthValuationWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/dashboard": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthDashboard",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthDashboard"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "currency",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{3}$"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "maxAgeDays",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 90,
              "minimum": 0,
              "maximum": 3650
            }
          }
        ]
      }
    },
    "/v1/wealth/projections": {
      "post": {
        "tags": [
          "Wealth"
        ],
        "operationId": "calculateWealthProjection",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthProjection"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WealthScenarioWrite"
              }
            }
          }
        }
      }
    },
    "/v1/wealth/projections/{id}": {
      "get": {
        "tags": [
          "Wealth"
        ],
        "operationId": "getWealthProjection",
        "responses": {
          "200": {
            "description": "Workspace-scoped wealth result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WealthProjection"
                }
              }
            }
          },
          "400": {
            "description": "Invalid wealth input"
          },
          "404": {
            "description": "Resource not found in workspace"
          },
          "409": {
            "description": "Version or funding conflict"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "operationId": "getHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "Service health",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "operationId": "getCurrentUser",
        "description": "Resolves the Supabase identity to the Moneybook user (linking or creating it on first sign-in) and returns it with the personal workspace.",
        "responses": {
          "200": {
            "description": "Authenticated user profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token"
          },
          "403": {
            "description": "User deactivated or email not verified for an existing account"
          }
        }
      }
    },
    "/v1/workspaces": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listMyWorkspaces",
        "description": "Workspaces the caller is an active member of, personal first.",
        "responses": {
          "200": {
            "description": "Workspaces",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Workspace"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "getWorkspace",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace with the caller's role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          },
          "404": {
            "description": "Not a member"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/export": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "exportWorkspace",
        "description": "OWNER or AUDITOR only. Download a ZIP containing a versioned financial JSON snapshot and original source files. Credentials and statement passwords are excluded. Export fails without returning a partial archive if a source file cannot be read. Maximum archive payload 100 MiB.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Private workspace archive",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "403": {
            "description": "Export permission required"
          },
          "404": {
            "description": "Workspace unavailable"
          },
          "413": {
            "description": "Archive exceeds limit"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/offboarding": {
      "post": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "offboardWorkspace",
        "description": "Active OWNER bearer session only. Confirmation must equal the workspace id. Deletes all workspace financial rows, memberships, invitations and API keys atomically, retaining only a minimal deletion receipt. Original files are queued for idempotent deletion by the authenticated job dispatcher. The personal workspace is replaced empty on next sign-in; shared workspaces disappear. This does not delete the Supabase identity or other workspaces. Requires exporting first if a copy is wanted; deletion cannot be undone through the app.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "confirmation"
                ],
                "additionalProperties": false,
                "properties": {
                  "confirmation": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Database deletion committed; file cleanup may remain pending",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "receiptId",
                    "pendingFiles"
                  ],
                  "properties": {
                    "receiptId": {
                      "type": "string"
                    },
                    "pendingFiles": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Confirmation mismatch"
          },
          "403": {
            "description": "Owner bearer session required"
          },
          "404": {
            "description": "Workspace unavailable"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/members": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaceMembers",
        "description": "Any member may list members.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Members",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkspaceMember"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not a member"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/members/{userId}": {
      "patch": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "updateWorkspaceMember",
        "description": "OWNER only. Changes role and optional access expiry. Membership changes are serialized per workspace so concurrent requests cannot remove the last active owner. The personal workspace's creator always stays owner. API keys cannot manage membership.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          },
          {
            "$ref": "#/components/parameters/UserId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkspaceMemberRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated member",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceMember"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an owner"
          },
          "404": {
            "description": "Workspace or member not found"
          },
          "409": {
            "description": "Would remove the last owner"
          }
        }
      },
      "delete": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "removeWorkspaceMember",
        "description": "OWNER user session only; API keys cannot manage membership. The last active owner and the personal workspace's creator cannot be removed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          },
          {
            "$ref": "#/components/parameters/UserId"
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "403": {
            "description": "Caller is not an owner"
          },
          "404": {
            "description": "Workspace or member not found"
          },
          "409": {
            "description": "Would remove the last owner"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/leave": {
      "post": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "leaveWorkspace",
        "description": "Leave a workspace you were invited to. You cannot leave your own personal workspace or leave it without an owner. API keys cannot leave workspaces.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "responses": {
          "204": {
            "description": "Left"
          },
          "403": {
            "description": "Personal workspace cannot be left"
          },
          "404": {
            "description": "Not a member"
          },
          "409": {
            "description": "Last owner"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/invites": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaceInvites",
        "description": "OWNER only.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Invites",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkspaceInvite"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "inviteWorkspaceMember",
        "description": "OWNER user session only; API keys cannot manage membership. Creates a pending invite for an email address (valid 14 days). An expired invitation or access grant may be reissued. No email is sent by the API; the invitee sees it under /v1/invites after signing in with that verified email.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteWorkspaceMemberRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pending invite",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceInvite"
                }
              }
            }
          },
          "400": {
            "description": "Invalid email or role"
          },
          "403": {
            "description": "Caller is not an owner"
          },
          "409": {
            "description": "Already a member or already invited"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/invites/{inviteId}": {
      "delete": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "revokeWorkspaceInvite",
        "description": "OWNER only. Revokes a pending invite.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          },
          {
            "$ref": "#/components/parameters/InviteId"
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked"
          },
          "404": {
            "description": "Invite not found"
          }
        }
      }
    },
    "/v1/workspaces/{workspaceId}/audit-events": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaceAuditEvents",
        "description": "Membership and access audit trail. Needs AUDIT (OWNER, AUDITOR).",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceIdPath"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkspaceAuditEvent"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Role lacks AUDIT"
          }
        }
      }
    },
    "/v1/invites": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listMyInvites",
        "description": "Pending, unexpired invites addressed to the caller's verified email.",
        "responses": {
          "200": {
            "description": "Invites",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkspaceInvite"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/invites/{inviteId}/accept": {
      "post": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "acceptWorkspaceInvite",
        "description": "Accept an invite addressed to the caller's verified email. Both the invitation and any granted access expiry must still be valid. API keys cannot accept invites.",
        "parameters": [
          {
            "$ref": "#/components/parameters/InviteId"
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace joined",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          },
          "403": {
            "description": "Email does not match or is not verified"
          },
          "404": {
            "description": "Invite not found"
          },
          "409": {
            "description": "Invite expired, revoked or already used"
          }
        }
      }
    },
    "/v1/accounts": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "operationId": "listAccounts",
        "parameters": [
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Size"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated user accounts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountPageResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Accounts"
        ],
        "operationId": "createAccount",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAccountRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          }
        }
      }
    },
    "/v1/accounts/{accountId}": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "operationId": "getAccount",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Accounts"
        ],
        "operationId": "updateAccount",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAccountRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Accounts"
        ],
        "operationId": "updateAccountViaPost",
        "description": "POST alias for clients or local environments where PATCH transport is unavailable.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAccountRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Accounts"
        ],
        "operationId": "deleteAccount",
        "description": "Delete an account and remove all linked transactions, import sessions, import records, and import batches for the authenticated user.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "204": {
            "description": "Account deleted"
          }
        }
      }
    },
    "/v1/currencies": {
      "get": {
        "tags": [
          "Currencies"
        ],
        "operationId": "listEnabledCurrencies",
        "responses": {
          "200": {
            "description": "Enabled currencies for account, preference, and transaction selectors",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Currency"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/categories": {
      "get": {
        "tags": [
          "Categories"
        ],
        "operationId": "listCategories",
        "parameters": [
          {
            "in": "query",
            "name": "kind",
            "schema": {
              "$ref": "#/components/schemas/CategoryKind"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Master and user categories available to the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Category"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Categories"
        ],
        "operationId": "createCategory",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User category created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Category"
                }
              }
            }
          }
        }
      }
    },
    "/v1/categories/{categoryId}": {
      "patch": {
        "tags": [
          "Categories"
        ],
        "operationId": "updateCategory",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User category updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Category"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Categories"
        ],
        "operationId": "deleteCategory",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryId"
          }
        ],
        "responses": {
          "204": {
            "description": "User category deleted"
          }
        }
      }
    },
    "/v1/imports": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "listImportSessions",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Size"
          },
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "in": "query",
            "name": "accountId",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "status",
            "description": "Restrict history to a single import lifecycle status.",
            "schema": {
              "type": "string",
              "enum": [
                "QUEUED",
                "PROCESSING",
                "AWAITING_CONFIRMATION",
                "NEEDS_REVIEW",
                "COMPLETED",
                "FAILED"
              ]
            }
          },
          {
            "in": "query",
            "name": "format",
            "description": "Restrict history to a single import source format.",
            "schema": {
              "type": "string",
              "enum": [
                "CSV",
                "PDF",
                "EXCEL"
              ]
            }
          },
          {
            "in": "query",
            "name": "presetKey",
            "description": "Restrict history to sessions created with a parser preset.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "startDate",
            "description": "Inclusive lower bound for import creation date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "endDate",
            "description": "Inclusive upper bound for import creation date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated import session history for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSessionPageResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "startImport",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "format",
                  "accountId"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "CSV",
                      "PDF",
                      "EXCEL"
                    ]
                  },
                  "accountId": {
                    "type": "string"
                  },
                  "presetKey": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Import session queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSession"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/preview": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "previewImport",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "format",
                  "accountId"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "CSV",
                      "PDF",
                      "EXCEL"
                    ]
                  },
                  "accountId": {
                    "type": "string"
                  },
                  "presetKey": {
                    "type": "string"
                  },
                  "statementPassword": {
                    "type": "string",
                    "description": "Optional. When set, used to open a password-protected PDF for this request only. If omitted, the account’s saved statement password (if any) is used."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Import parsed into a staged preview without committing transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSessionDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/bulk-preview": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "previewImportsBulk",
        "description": "Validate multiple uploaded statement files with one shared account, format, parser preset, and optional PDF password. Each file creates its own staged import session when accepted.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "files",
                  "format",
                  "accountId"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "CSV",
                      "PDF",
                      "EXCEL"
                    ]
                  },
                  "accountId": {
                    "type": "string"
                  },
                  "presetKey": {
                    "type": "string"
                  },
                  "statementPassword": {
                    "type": "string",
                    "description": "Optional. When set, used to open password-protected PDFs for this request only. If omitted, the account’s saved statement password (if any) is used."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-file staged previews and validation errors for the submitted batch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkImportPreviewResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "listImportBatches",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Size"
          },
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "in": "query",
            "name": "accountId",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "status",
            "description": "Restrict batch history to a single lifecycle status.",
            "schema": {
              "type": "string",
              "enum": [
                "QUEUED",
                "PROCESSING",
                "AWAITING_CONFIRMATION",
                "NEEDS_REVIEW",
                "COMPLETED",
                "FAILED"
              ]
            }
          },
          {
            "in": "query",
            "name": "format",
            "description": "Restrict batch history to a single import source format.",
            "schema": {
              "type": "string",
              "enum": [
                "CSV",
                "PDF",
                "EXCEL"
              ]
            }
          },
          {
            "in": "query",
            "name": "presetKey",
            "description": "Restrict batch history to batches created with a parser preset.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "startDate",
            "description": "Inclusive lower bound for batch creation date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "endDate",
            "description": "Inclusive upper bound for batch creation date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated import batch history for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchPageResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches/preview": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "previewImportBatch",
        "description": "Validate multiple same-format uploaded statement files as one persistent import batch. Each accepted file becomes a child import session retained for source preview and final confirmation.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "files",
                  "format",
                  "accountId"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "CSV",
                      "PDF",
                      "EXCEL"
                    ]
                  },
                  "accountId": {
                    "type": "string"
                  },
                  "presetKey": {
                    "type": "string"
                  },
                  "statementPassword": {
                    "type": "string",
                    "description": "Optional. When set, used to open password-protected PDFs for this request only. If omitted, the account’s saved statement password (if any) is used."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persistent batch detail with per-file staged previews and validation errors",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches/{batchId}": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "getImportBatch",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Import batch summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatch"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Imports"
        ],
        "operationId": "deleteImportBatch",
        "description": "Delete an uncommitted import batch and its staged child sessions. Batches with committed transactions cannot be deleted.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          }
        ],
        "responses": {
          "204": {
            "description": "Import batch deleted"
          }
        }
      }
    },
    "/v1/import-batches/{batchId}/detail": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "getImportBatchDetail",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Import batch with child sessions, staged rows, and file errors",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches/{batchId}/files": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "addFilesToImportBatch",
        "description": "Add more same-format files to an existing staged import batch. Files use the batch account, format, and parser preset. Completed batches are immutable and reject additional files.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "statementPassword": {
                    "type": "string",
                    "description": "Optional. When set, used to open password-protected PDFs for this request only. If omitted, the account’s saved statement password (if any) is used."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated batch detail after staging the additional files",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches/{batchId}/confirm": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "confirmImportBatch",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "All confirmable staged sessions in the batch were committed to transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches/{batchId}/review": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "acknowledgeImportBatchReview",
        "description": "Complete a review-only batch without creating ledger transactions. Intended for batches where every child session has no importable rows.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Review-only batch acknowledged",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/import-batches/{batchId}/sessions/{sessionId}": {
      "delete": {
        "tags": [
          "Imports"
        ],
        "operationId": "removeImportSessionFromBatch",
        "description": "Remove a staged, uncommitted child session from an import batch.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BatchId"
          },
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated batch detail after removing the staged session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportBatchDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/table-preview": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "previewImportTable",
        "description": "Extract candidate table columns and rows from an upload so users can build parser mappings without writing regex.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "format",
                  "accountId"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "CSV",
                      "PDF",
                      "EXCEL"
                    ]
                  },
                  "accountId": {
                    "type": "string"
                  },
                  "presetKey": {
                    "type": "string"
                  },
                  "statementPassword": {
                    "type": "string",
                    "description": "Optional. When set, used to open a password-protected PDF for this request only. If omitted, the account’s saved statement password (if any) is used."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Candidate table columns and sample rows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportTablePreviewResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "getImportSession",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Import session details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSession"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}/confirm": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "confirmImport",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Staged import committed to transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSession"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}/review": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "acknowledgeImportReview",
        "description": "Mark a review-only import as completed without creating ledger transactions. Intended for files that were retained for audit/preview but produced no importable rows.",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Review-only import acknowledged",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSession"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}/asset": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "getImportSessionAsset",
        "description": "Return the stored source asset for an import session so users can preview the original file while reviewing parser results.",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Stored import source asset",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}/asset-preview": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "previewImportSessionAsset",
        "description": "Return a browser-previewable source asset. For password-protected PDFs, the supplied one-time password or the account saved password may be used to return an unlocked PDF preview.",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportAssetPreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Previewable import source asset",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}/detail": {
      "get": {
        "tags": [
          "Imports"
        ],
        "operationId": "getImportSessionDetail",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Import session detailed records",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSessionDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports/{sessionId}/corrections": {
      "post": {
        "tags": [
          "Imports"
        ],
        "operationId": "submitImportCorrections",
        "description": "Apply review-time row edits to an uncommitted import session. Completed sessions are immutable and reject corrections.",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportCorrectionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Corrections applied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportSession"
                }
              }
            }
          }
        }
      }
    },
    "/v1/ops/logs/stream": {
      "get": {
        "tags": [
          "Ops"
        ],
        "operationId": "streamLogs",
        "description": "ADMIN-only development heartbeat stream. Disabled in production; local connections close after 60 seconds.",
        "responses": {
          "200": {
            "description": "Server-sent event log stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Log stream disabled for this environment"
          }
        }
      }
    },
    "/v1/transactions": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "listTransactions",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Size"
          },
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "in": "query",
            "name": "month",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-[0-9]{2}$"
            }
          },
          {
            "in": "query",
            "name": "accountId",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "currency",
            "description": "Restrict the ledger response to a single ISO 4217 transaction currency.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{3}$"
            }
          },
          {
            "in": "query",
            "name": "startDate",
            "description": "Inclusive lower bound for transaction posted date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "endDate",
            "description": "Inclusive upper bound for transaction posted date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "category",
            "description": "Restrict the ledger response to one normalized transaction category.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "merchant",
            "description": "Case-insensitive substring match on the merchant name. Rows with a null or empty merchant never match a non-blank value.\n",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "source",
            "description": "Restrict the ledger response to one transaction source.",
            "schema": {
              "type": "string",
              "enum": [
                "MANUAL",
                "IMPORT_CSV",
                "IMPORT_PDF",
                "IMPORT_EXCEL",
                "API_INGESTION",
                "ENRICHED"
              ]
            }
          },
          {
            "in": "query",
            "name": "direction",
            "description": "Restrict the ledger response to income or spending movement.",
            "schema": {
              "type": "string",
              "enum": [
                "INCOME",
                "SPENDING"
              ]
            }
          },
          {
            "in": "query",
            "name": "amountMinorMin",
            "description": "Inclusive lower bound on signed amount in minor units (same as Money.amountMinor). Outflows are negative; omit for no lower bound.\n",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "in": "query",
            "name": "amountMinorMax",
            "description": "Inclusive upper bound on signed amount in minor units. Omit for no upper bound.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionPageResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Transactions"
        ],
        "operationId": "createTransaction",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTransactionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Transaction ingested",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/export": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "exportTransactions",
        "description": "CSV export of the active workspace's ledger. Needs EXPORT (OWNER, AUDITOR); EDITOR and VIEWER get 403.",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceHeader"
          },
          {
            "in": "query",
            "name": "accountId",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "startDate",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "endDate",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV with header row id,postedAt,accountId,description,merchant,amountMinor,currency,category,source",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "Role lacks EXPORT"
          }
        }
      }
    },
    "/v1/transactions/bulk": {
      "post": {
        "tags": [
          "Transactions"
        ],
        "operationId": "bulkCreateTransactions",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkCreateTransactionsRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Transactions ingested",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkCreateTransactionsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/inter-account/link-candidates": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "listInterAccountLinkCandidates",
        "summary": "Scan for proposed inter-account transfer pairs",
        "description": "Returns unlinked transaction pairs where one leg is an outflow and the other an inflow on a different account, same currency, equal and opposite amounts, and posted dates within ±dayWindow days. Use for batch review before creating links via POST .../inter-account-link.\n",
        "parameters": [
          {
            "in": "query",
            "name": "dayWindow",
            "description": "Half-width in days for posted-date proximity (0–30). Default 1.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1,
              "minimum": 0,
              "maximum": 30
            }
          },
          {
            "in": "query",
            "name": "limit",
            "description": "Maximum pairs returned (1–500). Default 200.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 200,
              "minimum": 1,
              "maximum": 500
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Candidate pairs (outflow first, inflow second)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InterAccountLinkCandidate"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/{transactionId}": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "getTransaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Transactions"
        ],
        "operationId": "updateTransaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTransactionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Transactions"
        ],
        "operationId": "updateTransactionViaPost",
        "description": "POST alias for clients or local environments where PATCH transport is unavailable.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTransactionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Transactions"
        ],
        "operationId": "deleteTransaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "responses": {
          "204": {
            "description": "Transaction deleted"
          }
        }
      }
    },
    "/v1/transactions/{transactionId}/inter-account-suggestions": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "listInterAccountSuggestions",
        "summary": "Suggest counterpart transactions for an inter-account transfer link",
        "description": "Returns transactions on other accounts with the opposite signed amount (same currency), posted within ±1 day, that are not already linked. Empty when this transaction is already linked.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Candidate peer transactions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Transaction"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/{transactionId}/inter-account-link": {
      "post": {
        "tags": [
          "Transactions"
        ],
        "operationId": "createInterAccountLink",
        "summary": "Link two transactions as an inter-account transfer",
        "description": "Pairs an outflow (negative amount) on one account with an inflow (positive amount) on another. Same currency and equal absolute amounts required. Both legs are excluded from income/spending insights.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInterAccountLinkRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Link created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterAccountLinkCreatedResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Transactions"
        ],
        "operationId": "deleteInterAccountLink",
        "summary": "Remove inter-account transfer link for this transaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/TransactionId"
          }
        ],
        "responses": {
          "204": {
            "description": "Link removed"
          }
        }
      }
    },
    "/v1/goals": {
      "get": {
        "tags": [
          "Goals"
        ],
        "operationId": "listGoals",
        "responses": {
          "200": {
            "description": "User goals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Goal"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Goals"
        ],
        "operationId": "createGoal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGoalRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Goal created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Goal"
                }
              }
            }
          }
        }
      }
    },
    "/v1/goals/{goalId}": {
      "get": {
        "tags": [
          "Goals"
        ],
        "operationId": "getGoal",
        "parameters": [
          {
            "$ref": "#/components/parameters/GoalId"
          }
        ],
        "responses": {
          "200": {
            "description": "Goal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Goal"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Goals"
        ],
        "operationId": "updateGoal",
        "parameters": [
          {
            "$ref": "#/components/parameters/GoalId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGoalRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Goal updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Goal"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Goals"
        ],
        "operationId": "deleteGoal",
        "parameters": [
          {
            "$ref": "#/components/parameters/GoalId"
          }
        ],
        "responses": {
          "204": {
            "description": "Goal deleted"
          }
        }
      }
    },
    "/v1/insights": {
      "get": {
        "tags": [
          "Insights"
        ],
        "operationId": "listInsights",
        "parameters": [
          {
            "in": "query",
            "name": "month",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-[0-9]{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Insights feed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Insight"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Insights"
        ],
        "operationId": "triggerInsightGeneration",
        "responses": {
          "202": {
            "description": "Insight job triggered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobReference"
                }
              }
            }
          }
        }
      }
    },
    "/v1/insights/report": {
      "get": {
        "tags": [
          "Insights"
        ],
        "operationId": "getInsightReport",
        "parameters": [
          {
            "in": "query",
            "name": "months",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2400,
              "default": 12
            },
            "description": "Rolling window length in months ending in the current calendar month. When both periodStart and periodEnd are set, this parameter is ignored. If omitted and no period is set, the server uses 12.\n"
          },
          {
            "in": "query",
            "name": "periodStart",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}$"
            },
            "description": "Inclusive start month (YYYY-MM). Requires periodEnd; overrides months."
          },
          {
            "in": "query",
            "name": "periodEnd",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}$"
            },
            "description": "Inclusive end month (YYYY-MM). Requires periodStart; overrides months."
          },
          {
            "in": "query",
            "name": "currency",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "accountId",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated cash-flow report for chart and pattern widgets",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InsightReport"
                }
              }
            }
          }
        }
      }
    },
    "/v1/jobs": {
      "get": {
        "tags": [
          "Jobs"
        ],
        "operationId": "listJobs",
        "description": "Latest 200 jobs owned by the active authorized workspace. Unowned historical and global campaign records are excluded. Messages are controlled summaries, never raw exception text.",
        "responses": {
          "200": {
            "description": "Job executions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/JobStatus"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/jobs/{jobId}": {
      "get": {
        "tags": [
          "Jobs"
        ],
        "operationId": "getJob",
        "description": "Active-workspace job only; foreign or unowned identifiers return 404.",
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobStatus"
                }
              }
            }
          },
          "404": {
            "description": "Job not found in the active authorized workspace"
          }
        }
      }
    },
    "/v1/notifications/preferences": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "operationId": "getNotificationPreferences",
        "responses": {
          "200": {
            "description": "Notification preferences",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationPreference"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Notifications"
        ],
        "operationId": "upsertNotificationPreferences",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationPreference"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preferences updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationPreference"
                }
              }
            }
          }
        }
      }
    },
    "/v1/notifications/history": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "operationId": "listNotificationHistory",
        "responses": {
          "200": {
            "description": "In-app notification history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationEvent"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/settings/preferences": {
      "get": {
        "tags": [
          "Settings"
        ],
        "operationId": "getUserPreferences",
        "responses": {
          "200": {
            "description": "Current user workspace preferences",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserPreference"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Settings"
        ],
        "operationId": "updateUserPreferences",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserPreferenceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User preferences updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserPreference"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Settings"
        ],
        "operationId": "updateUserPreferencesViaPost",
        "description": "POST alias for clients or local environments where PATCH transport is unavailable.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserPreferenceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User preferences updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserPreference"
                }
              }
            }
          }
        }
      }
    },
    "/v1/settings/reset-data": {
      "post": {
        "tags": [
          "Settings"
        ],
        "operationId": "resetWorkspaceData",
        "description": "OWNER only. Deletes all data in the active workspace plus the caller's own notification and preference state.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetWorkspaceDataRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Workspace data reset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResetWorkspaceDataResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/settings/api-keys": {
      "get": {
        "tags": [
          "Settings"
        ],
        "operationId": "listApiKeys",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Size"
          },
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "deleted"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated API keys for the current user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyPageResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Settings"
        ],
        "operationId": "createApiKey",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created with one-time plaintext secret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                }
              }
            }
          }
        }
      }
    },
    "/v1/settings/api-keys/{apiKeyId}": {
      "get": {
        "tags": [
          "Settings"
        ],
        "operationId": "getApiKey",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiKeyId"
          }
        ],
        "responses": {
          "200": {
            "description": "API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Settings"
        ],
        "operationId": "updateApiKey",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiKeyId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateApiKeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Settings"
        ],
        "operationId": "revokeApiKey",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiKeyId"
          }
        ],
        "responses": {
          "204": {
            "description": "API key revoked"
          }
        }
      }
    },
    "/v1/settings/api-keys/{apiKeyId}/rotate": {
      "post": {
        "tags": [
          "Settings"
        ],
        "operationId": "rotateApiKey",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiKeyId"
          }
        ],
        "responses": {
          "200": {
            "description": "API key rotated with one-time plaintext secret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/users": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listAdminUsers",
        "description": "Platform admins only (Supabase `app_metadata.role = admin`). Users are created by signing in through Supabase Auth.",
        "responses": {
          "200": {
            "description": "Application users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdminUser"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/users/{userId}": {
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "updateAdminUser",
        "description": "Activate or deactivate a user. Roles and credentials are managed in Supabase Auth.",
        "parameters": [
          {
            "$ref": "#/components/parameters/UserId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAdminUserRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminUser"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/notification-templates": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listNotificationTemplates",
        "responses": {
          "200": {
            "description": "Notification templates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationTemplate"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "createNotificationTemplate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationTemplateUpsert"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationTemplate"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/notification-templates/{templateId}": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "getNotificationTemplate",
        "parameters": [
          {
            "in": "path",
            "name": "templateId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Notification template",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationTemplate"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "updateNotificationTemplate",
        "parameters": [
          {
            "in": "path",
            "name": "templateId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationTemplatePatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationTemplate"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin"
        ],
        "operationId": "deleteNotificationTemplate",
        "parameters": [
          {
            "in": "path",
            "name": "templateId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Template deleted"
          }
        }
      }
    },
    "/v1/admin/notification-rules": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listNotificationRules",
        "responses": {
          "200": {
            "description": "Notification rules",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationRule"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "createNotificationRule",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationRuleUpsert"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Rule created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationRule"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/notification-rules/{ruleId}": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "getNotificationRule",
        "parameters": [
          {
            "in": "path",
            "name": "ruleId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Notification rule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationRule"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "updateNotificationRule",
        "parameters": [
          {
            "in": "path",
            "name": "ruleId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationRulePatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rule updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationRule"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin"
        ],
        "operationId": "deleteNotificationRule",
        "parameters": [
          {
            "in": "path",
            "name": "ruleId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Rule deleted"
          }
        }
      }
    },
    "/v1/admin/notification-campaigns/{campaignId}/trigger": {
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "triggerNotificationCampaign",
        "parameters": [
          {
            "in": "path",
            "name": "campaignId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Campaign scheduled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobReference"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/db/parser-presets": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listParserPresets",
        "responses": {
          "200": {
            "description": "Parser presets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ParserPreset"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "createParserPreset",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParserPresetUpsert"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Parser preset created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParserPreset"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/db/parser-presets/{presetId}": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "getParserPreset",
        "parameters": [
          {
            "in": "path",
            "name": "presetId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Parser preset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParserPreset"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "updateParserPreset",
        "parameters": [
          {
            "in": "path",
            "name": "presetId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParserPresetPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parser preset updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParserPreset"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin"
        ],
        "operationId": "deleteParserPreset",
        "parameters": [
          {
            "in": "path",
            "name": "presetId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Parser preset deleted"
          }
        }
      }
    },
    "/v1/admin/currencies": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listCurrencies",
        "responses": {
          "200": {
            "description": "All ISO currencies with Moneybook enablement state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Currency"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/currencies/{currencyCode}": {
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "updateCurrency",
        "parameters": [
          {
            "$ref": "#/components/parameters/CurrencyCode"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCurrencyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Currency updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Currency"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/categories": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listMasterCategories",
        "responses": {
          "200": {
            "description": "Master category catalog",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Category"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "createMasterCategory",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Master category created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Category"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/categories/{categoryId}": {
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "updateMasterCategory",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Master category updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Category"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin"
        ],
        "operationId": "deleteMasterCategory",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryId"
          }
        ],
        "responses": {
          "204": {
            "description": "Master category deleted"
          }
        }
      }
    },
    "/v1/admin/db/tables": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listDatabaseTables",
        "responses": {
          "200": {
            "description": "Database tables",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/db/tables/{table}/rows": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listDatabaseRows",
        "description": "Active verified ADMIN only. Credential/password/token fields, provider configuration, historical job messages and binary cells are redacted. Page must be nonnegative; size is 1..200.",
        "parameters": [
          {
            "in": "path",
            "name": "table",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "in": "query",
            "name": "size",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Table rows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminRowsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Unsupported schema identifier, protected table, pagination or primary-key match"
          },
          "403": {
            "description": "Active confirmed platform administrator required"
          }
        }
      },
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "insertDatabaseRow",
        "summary": "Insert a row (active verified ADMIN; schema validated and audited)",
        "description": "Access-control, credential, queue and audit tables are read-only here. Use dedicated domain APIs. Mutations are atomic with a metadata-only audit; values are never recorded in that audit.",
        "parameters": [
          {
            "in": "path",
            "name": "table",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InsertDatabaseRowRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Inserted row with credential and binary redaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Unsupported schema identifier, protected table, pagination or primary-key match"
          },
          "403": {
            "description": "Active confirmed platform administrator required"
          }
        }
      },
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "patchDatabaseRow",
        "description": "Active verified ADMIN only. Requires all primary-key columns in match. Security/credential/queue/audit tables are read-only. Mutation and metadata-only audit commit atomically; sensitive response cells are redacted.",
        "summary": "Patch a row (ADMIN; single-row match enforced)",
        "parameters": [
          {
            "in": "path",
            "name": "table",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchDatabaseRowRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated row with sensitive-cell redaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Unsupported schema identifier, protected table, pagination or primary-key match"
          },
          "403": {
            "description": "Active confirmed platform administrator required"
          }
        }
      }
    },
    "/v1/admin/db/tables/{table}/delete": {
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "deleteDatabaseRow",
        "description": "Active verified ADMIN only. Requires all primary-key columns in match. Security/credential/queue/audit tables are read-only. Mutation and metadata-only audit commit atomically; sensitive response cells are redacted.",
        "summary": "Delete a row (ADMIN; single-row match enforced)",
        "parameters": [
          {
            "in": "path",
            "name": "table",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteDatabaseRowRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Row deleted"
          },
          "400": {
            "description": "Unsupported schema identifier, protected table, pagination or primary-key match"
          },
          "403": {
            "description": "Active confirmed platform administrator required"
          }
        }
      }
    },
    "/v1/fx-rates": {
      "get": {
        "tags": [
          "FxRates"
        ],
        "operationId": "listFxRates",
        "parameters": [
          {
            "in": "query",
            "name": "base",
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 3
            }
          }
        ],
        "responses": {
          "200": {
            "description": "FX rates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FxRate"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      },
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Spective-Api-Key"
      }
    },
    "parameters": {
      "WorkspaceHeader": {
        "in": "header",
        "name": "X-Spective-Workspace-Id",
        "required": false,
        "description": "Active workspace for workspace-scoped operations. Defaults to the caller's personal workspace.",
        "schema": {
          "type": "string"
        }
      },
      "WorkspaceIdPath": {
        "in": "path",
        "name": "workspaceId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "InviteId": {
        "in": "path",
        "name": "inviteId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "AccountId": {
        "in": "path",
        "name": "accountId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "SessionId": {
        "in": "path",
        "name": "sessionId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "BatchId": {
        "in": "path",
        "name": "batchId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "CurrencyCode": {
        "in": "path",
        "name": "currencyCode",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 3,
          "maxLength": 3
        }
      },
      "CategoryId": {
        "in": "path",
        "name": "categoryId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "TransactionId": {
        "in": "path",
        "name": "transactionId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "GoalId": {
        "in": "path",
        "name": "goalId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "ApiKeyId": {
        "in": "path",
        "name": "apiKeyId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "UserId": {
        "in": "path",
        "name": "userId",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "Page": {
        "in": "query",
        "name": "page",
        "description": "1-based page number.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "Size": {
        "in": "query",
        "name": "size",
        "description": "Number of records per page. The server caps this at 100.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "Search": {
        "in": "query",
        "name": "search",
        "description": "Resource-specific text search.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "WealthPositionWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "kind",
          "assetClass",
          "liquidity",
          "ownershipShare",
          "currency",
          "openedOn",
          "sourceReference",
          "confidence",
          "included"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "kind": {
            "type": "string",
            "enum": [
              "ASSET",
              "LIABILITY"
            ]
          },
          "assetClass": {
            "type": "string",
            "enum": [
              "CASH",
              "DEPOSIT",
              "MARKET",
              "RETIREMENT",
              "GOLD",
              "PROPERTY",
              "VEHICLE",
              "BUSINESS",
              "EMPLOYEE_EQUITY",
              "OTHER"
            ]
          },
          "liquidity": {
            "type": "string",
            "enum": [
              "LIQUID",
              "RESTRICTED",
              "ILLIQUID"
            ]
          },
          "ownershipShare": {
            "type": "string",
            "pattern": "^(0(\\.[0-9]{1,6})?|1(\\.0{1,6})?)$"
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "openedOn": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "confidence": {
            "type": "string",
            "enum": [
              "VERIFIED",
              "ESTIMATED"
            ]
          },
          "included": {
            "type": "boolean"
          },
          "linkedAccountId": {
            "type": "string",
            "nullable": true
          },
          "evidencePositionId": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "WealthCompensationWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "employer",
          "designation",
          "effectiveDate",
          "currency",
          "annualCtcMinor",
          "grossMonthlyMinor",
          "takeHomeMonthlyMinor",
          "tdsMonthlyMinor",
          "employeePfMonthlyMinor",
          "employerPfMonthlyMinor",
          "employerNpsMonthlyMinor",
          "bonusMinor",
          "sourceReference"
        ],
        "properties": {
          "employer": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "designation": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "annualCtcMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "grossMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "takeHomeMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "tdsMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "employeePfMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "employerPfMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "employerNpsMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "bonusMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "WealthEventWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "label",
          "effectiveDate",
          "kind",
          "amountMinor",
          "currency",
          "sourceReference",
          "hidden"
        ],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "kind": {
            "type": "string",
            "enum": [
              "NOTE",
              "CONTRIBUTION",
              "WITHDRAWAL",
              "INVESTMENT_GAIN",
              "REVALUATION",
              "ADJUSTMENT"
            ]
          },
          "amountMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "hidden": {
            "type": "boolean"
          }
        }
      },
      "WealthScenarioWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "asOf",
          "currency",
          "monthlyContributionMinor",
          "annualReturnPercent",
          "annualContributionGrowthPercent",
          "inflationPercent",
          "years",
          "targetAmountMinor"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "asOf": {
            "type": "string",
            "format": "date"
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "startingAmountMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 24,
            "nullable": true
          },
          "monthlyContributionMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "annualReturnPercent": {
            "type": "number",
            "minimum": -50,
            "maximum": 50
          },
          "annualContributionGrowthPercent": {
            "type": "number",
            "minimum": -50,
            "maximum": 50
          },
          "inflationPercent": {
            "type": "number",
            "minimum": 0,
            "maximum": 30
          },
          "years": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "targetAmountMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          }
        }
      },
      "WealthAllocationWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "goalId",
          "sourceId",
          "currency",
          "amountMinor"
        ],
        "properties": {
          "goalId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "sourceId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "amountMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          }
        }
      },
      "WealthValuationWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "valueMinor",
          "effectiveDate",
          "sourceReference",
          "confidence"
        ],
        "properties": {
          "valueMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 24
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "confidence": {
            "type": "string",
            "enum": [
              "VERIFIED",
              "ESTIMATED"
            ]
          }
        }
      },
      "WealthPosition": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "version",
          "recordedAt",
          "archived",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "version": {
            "type": "integer"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "archived": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/WealthPositionWrite"
          }
        }
      },
      "WealthCompensation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "version",
          "recordedAt",
          "archived",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "version": {
            "type": "integer"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "archived": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/WealthCompensationWrite"
          }
        }
      },
      "WealthEvent": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "version",
          "recordedAt",
          "archived",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "version": {
            "type": "integer"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "archived": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/WealthEventWrite"
          }
        }
      },
      "WealthScenario": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "version",
          "recordedAt",
          "archived",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "version": {
            "type": "integer"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "archived": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/WealthScenarioWrite"
          }
        }
      },
      "WealthAllocation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "version",
          "recordedAt",
          "archived",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "version": {
            "type": "integer"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "archived": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/WealthAllocationWrite"
          }
        }
      },
      "WealthValuation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "positionId",
          "valueMinor",
          "effectiveDate",
          "sourceReference",
          "confidence",
          "recordedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "positionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "valueMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "confidence": {
            "type": "string",
            "enum": [
              "VERIFIED",
              "ESTIMATED"
            ]
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WealthLine": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "kind",
          "assetClass",
          "liquidity",
          "valueMinor",
          "financial",
          "liquid",
          "included",
          "status",
          "effectiveDate",
          "sourceReference"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "assetClass": {
            "type": "string"
          },
          "liquidity": {
            "type": "string"
          },
          "valueMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80,
            "nullable": true
          },
          "financial": {
            "type": "boolean"
          },
          "liquid": {
            "type": "boolean"
          },
          "included": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "VERIFIED",
              "ESTIMATED",
              "STALE",
              "MISSING",
              "EXCLUDED"
            ]
          },
          "effectiveDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "sourceReference": {
            "type": "string"
          }
        }
      },
      "WealthSnapshot": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "asOf",
          "totalMinor",
          "financialMinor",
          "liquidMinor",
          "assetsMinor",
          "liabilitiesMinor",
          "complete",
          "lines"
        ],
        "properties": {
          "asOf": {
            "type": "string",
            "format": "date"
          },
          "totalMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "financialMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "liquidMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "assetsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "liabilitiesMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "complete": {
            "type": "boolean"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WealthLine"
            }
          }
        }
      },
      "WealthBridge": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "startingMinor",
          "contributionsMinor",
          "investmentGainsMinor",
          "revaluationsMinor",
          "adjustmentsMinor",
          "unexplainedMinor",
          "endingMinor",
          "complete"
        ],
        "properties": {
          "startingMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "contributionsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "investmentGainsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "revaluationsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "adjustmentsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "unexplainedMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "endingMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "complete": {
            "type": "boolean"
          }
        }
      },
      "WealthMilestone": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "label",
          "date",
          "amountMinor"
        ],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "amountMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 80
          }
        }
      },
      "WealthGoalProgress": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "targetMinor",
          "allocatedMinor",
          "shortfallMinor",
          "targetDate"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "targetMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "allocatedMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "shortfallMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "targetDate": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "WealthDashboard": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "currency",
          "currencyScale",
          "knowledgeCutoff",
          "sourceVersion",
          "modelVersion",
          "current",
          "history",
          "bridge",
          "milestones",
          "goals"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "currencyScale": {
            "type": "integer"
          },
          "knowledgeCutoff": {
            "type": "string",
            "format": "date-time"
          },
          "sourceVersion": {
            "type": "string"
          },
          "modelVersion": {
            "type": "string"
          },
          "current": {
            "$ref": "#/components/schemas/WealthSnapshot"
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WealthSnapshot"
            }
          },
          "bridge": {
            "$ref": "#/components/schemas/WealthBridge"
          },
          "milestones": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WealthMilestone"
            }
          },
          "goals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WealthGoalProgress"
            }
          }
        }
      },
      "WealthProjectionPoint": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "month",
          "date",
          "nominalMinor",
          "realMinor",
          "contributionsMinor",
          "gainsMinor"
        ],
        "properties": {
          "month": {
            "type": "integer"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "nominalMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "realMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "contributionsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "gainsMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          }
        }
      },
      "WealthProjection": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "recordedAt",
          "modelVersion",
          "sourceVersion",
          "startingSource",
          "assumptions",
          "startingMinor",
          "points",
          "targetDate",
          "requiredMonthlyMinor",
          "warning"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "modelVersion": {
            "type": "string"
          },
          "sourceVersion": {
            "type": "string"
          },
          "startingSource": {
            "type": "string",
            "enum": [
              "VERIFIED_SNAPSHOT",
              "USER_DEFINED"
            ]
          },
          "assumptions": {
            "$ref": "#/components/schemas/WealthScenarioWrite"
          },
          "startingMinor": {
            "type": "string",
            "pattern": "^-?(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WealthProjectionPoint"
            }
          },
          "targetDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "requiredMonthlyMinor": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)$",
            "maxLength": 80
          },
          "warning": {
            "type": "string"
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "service",
          "timestamp"
        ],
        "properties": {
          "status": {
            "type": "string"
          },
          "service": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MeResponse": {
        "type": "object",
        "required": [
          "id",
          "email",
          "role",
          "personalWorkspaceId"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Moneybook user id (legacy TEXT id; the Supabase `sub` for users created after the migration)."
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "USER",
              "ADMIN"
            ],
            "description": "Platform role, from Supabase `app_metadata.role`."
          },
          "authUserId": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Supabase auth.users id (`sub`)."
          },
          "personalWorkspaceId": {
            "type": "string"
          },
          "activeWorkspaceId": {
            "type": "string",
            "nullable": true,
            "description": "Workspace named by X-Spective-Workspace-Id when the caller can read it, otherwise null."
          }
        }
      },
      "AdminUser": {
        "type": "object",
        "required": [
          "id",
          "email",
          "role",
          "active",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "USER",
              "ADMIN"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "authUserId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpdateAdminUserRequest": {
        "type": "object",
        "required": [
          "active"
        ],
        "properties": {
          "active": {
            "type": "boolean"
          }
        }
      },
      "WorkspaceRole": {
        "type": "string",
        "enum": [
          "OWNER",
          "EDITOR",
          "VIEWER",
          "AUDITOR"
        ]
      },
      "Workspace": {
        "type": "object",
        "required": [
          "id",
          "name",
          "kind",
          "role",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "PERSONAL",
              "SHARED"
            ]
          },
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          },
          "accessExpiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the caller's membership expires; null means no expiry."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WorkspaceMember": {
        "type": "object",
        "required": [
          "userId",
          "email",
          "role",
          "createdAt"
        ],
        "properties": {
          "userId": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "WorkspaceInvite": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "workspaceName",
          "email",
          "role",
          "status",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string"
          },
          "workspaceName": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          },
          "accessExpiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "ACCEPTED",
              "REVOKED"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InviteWorkspaceMemberRequest": {
        "type": "object",
        "required": [
          "email",
          "role"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string",
            "enum": [
              "EDITOR",
              "VIEWER",
              "AUDITOR"
            ]
          },
          "accessExpiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Optional end of the granted access, typically for auditors."
          }
        }
      },
      "UpdateWorkspaceMemberRequest": {
        "type": "object",
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "WorkspaceAuditEvent": {
        "type": "object",
        "required": [
          "id",
          "action",
          "details",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "actorUserId": {
            "type": "string",
            "nullable": true
          },
          "action": {
            "type": "string"
          },
          "target": {
            "type": "string",
            "nullable": true
          },
          "details": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Account": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "type",
          "currency",
          "isInUse",
          "statementPasswordConfigured",
          "closed"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "BANK",
              "CREDIT_CARD",
              "CASH",
              "INVESTMENT"
            ]
          },
          "currency": {
            "type": "string"
          },
          "isInUse": {
            "type": "boolean",
            "description": "True when the account is referenced by transactions or import sessions and cannot be deleted."
          },
          "statementPasswordConfigured": {
            "type": "boolean",
            "description": "True when a write-only PDF statement password is saved for this account. The password value is never returned."
          },
          "closed": {
            "type": "boolean",
            "description": "When true, the account is read-only in Studio until reopened; new imports and manual/API transactions are rejected."
          }
        }
      },
      "PageMetadata": {
        "type": "object",
        "required": [
          "page",
          "size",
          "totalItems",
          "totalPages",
          "hasNext",
          "hasPrevious"
        ],
        "properties": {
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "size": {
            "type": "integer",
            "minimum": 1
          },
          "totalItems": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "totalPages": {
            "type": "integer",
            "minimum": 0
          },
          "hasNext": {
            "type": "boolean"
          },
          "hasPrevious": {
            "type": "boolean"
          }
        }
      },
      "AccountPageResponse": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Account"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageMetadata"
          }
        }
      },
      "UserPreference": {
        "type": "object",
        "required": [
          "userId",
          "locale",
          "baseCurrency"
        ],
        "properties": {
          "userId": {
            "type": "string"
          },
          "locale": {
            "type": "string"
          },
          "baseCurrency": {
            "type": "string"
          },
          "defaultAccountId": {
            "type": "string",
            "nullable": true
          },
          "onboardingDismissedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "UpdateUserPreferenceRequest": {
        "type": "object",
        "properties": {
          "locale": {
            "type": "string"
          },
          "baseCurrency": {
            "type": "string"
          },
          "defaultAccountId": {
            "type": "string"
          },
          "onboardingDismissedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ResetWorkspaceDataRequest": {
        "type": "object",
        "required": [
          "confirmation"
        ],
        "properties": {
          "confirmation": {
            "type": "string",
            "enum": [
              "delete"
            ],
            "description": "Must be exactly \"delete\" to confirm a destructive reset."
          }
        }
      },
      "ResetWorkspaceDataDeletedCounts": {
        "type": "object",
        "required": [
          "accounts",
          "apiKeys",
          "assets",
          "categories",
          "goalProgress",
          "goals",
          "importRecords",
          "importBatches",
          "importSessions",
          "insightSnapshots",
          "jobAudits",
          "notificationEvents",
          "notificationPreferences",
          "transactionAdjustments",
          "transactions"
        ],
        "properties": {
          "accounts": {
            "type": "integer",
            "format": "int64"
          },
          "apiKeys": {
            "type": "integer",
            "format": "int64"
          },
          "assets": {
            "type": "integer",
            "format": "int64"
          },
          "categories": {
            "type": "integer",
            "format": "int64"
          },
          "goalProgress": {
            "type": "integer",
            "format": "int64"
          },
          "goals": {
            "type": "integer",
            "format": "int64"
          },
          "importRecords": {
            "type": "integer",
            "format": "int64"
          },
          "importBatches": {
            "type": "integer",
            "format": "int64"
          },
          "importSessions": {
            "type": "integer",
            "format": "int64"
          },
          "insightSnapshots": {
            "type": "integer",
            "format": "int64"
          },
          "jobAudits": {
            "type": "integer",
            "format": "int64"
          },
          "notificationEvents": {
            "type": "integer",
            "format": "int64"
          },
          "notificationPreferences": {
            "type": "integer",
            "format": "int64"
          },
          "transactionAdjustments": {
            "type": "integer",
            "format": "int64"
          },
          "transactions": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ResetWorkspaceDataResponse": {
        "type": "object",
        "required": [
          "userId",
          "workspaceId",
          "resetAt",
          "deleted"
        ],
        "properties": {
          "userId": {
            "type": "string",
            "description": "User who performed the reset."
          },
          "workspaceId": {
            "type": "string"
          },
          "resetAt": {
            "type": "string",
            "format": "date-time"
          },
          "deleted": {
            "$ref": "#/components/schemas/ResetWorkspaceDataDeletedCounts"
          }
        }
      },
      "CreateAccountRequest": {
        "type": "object",
        "required": [
          "name",
          "type",
          "currency"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "BANK",
              "CREDIT_CARD",
              "CASH",
              "INVESTMENT"
            ]
          },
          "currency": {
            "type": "string"
          },
          "initialBalance": {
            "description": "Optional opening ledger balance to create with the account. When omitted or zero, no opening transaction is created.",
            "$ref": "#/components/schemas/Money"
          },
          "statementPassword": {
            "type": "string",
            "format": "password",
            "nullable": true,
            "description": "Optional write-only PDF statement password saved with this account for future imports."
          }
        }
      },
      "UpdateAccountRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "BANK",
              "CREDIT_CARD",
              "CASH",
              "INVESTMENT"
            ]
          },
          "currency": {
            "type": "string"
          },
          "statementPassword": {
            "type": "string",
            "format": "password",
            "nullable": true,
            "description": "Optional write-only replacement PDF statement password. Omit or send blank to keep the current saved password."
          },
          "clearStatementPassword": {
            "type": "boolean",
            "default": false,
            "description": "Clears the saved PDF statement password when true."
          },
          "closed": {
            "type": "boolean",
            "description": "Set true to close the account (read-only, no new imports or transactions). Set false to reopen. Other fields cannot change while the account stays closed unless reopening in the same request."
          }
        }
      },
      "Currency": {
        "type": "object",
        "required": [
          "code",
          "name",
          "symbol",
          "decimalPlaces",
          "enabled"
        ],
        "properties": {
          "code": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3
          },
          "name": {
            "type": "string"
          },
          "symbol": {
            "type": "string"
          },
          "decimalPlaces": {
            "type": "integer"
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "UpdateCurrencyRequest": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "ImportSession": {
        "type": "object",
        "required": [
          "id",
          "status",
          "format",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "batchId": {
            "type": "string",
            "nullable": true
          },
          "accountId": {
            "type": "string",
            "nullable": true
          },
          "fileName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "QUEUED",
              "PROCESSING",
              "AWAITING_CONFIRMATION",
              "NEEDS_REVIEW",
              "COMPLETED",
              "FAILED"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV",
              "PDF",
              "EXCEL"
            ]
          },
          "presetKey": {
            "type": "string"
          },
          "parseJobId": {
            "type": "string",
            "nullable": true
          },
          "parseCorrelationId": {
            "type": "string",
            "nullable": true
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ImportAssetPreviewRequest": {
        "type": "object",
        "properties": {
          "statementPassword": {
            "type": "string",
            "format": "password",
            "description": "Optional one-time PDF password used only for this preview request. If omitted, the account saved password is used when available."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ImportBatch": {
        "type": "object",
        "required": [
          "id",
          "accountId",
          "status",
          "format",
          "presetKey",
          "fileCount",
          "recordCount",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "accountId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "QUEUED",
              "PROCESSING",
              "AWAITING_CONFIRMATION",
              "NEEDS_REVIEW",
              "COMPLETED",
              "FAILED"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV",
              "PDF",
              "EXCEL"
            ]
          },
          "presetKey": {
            "type": "string"
          },
          "fileCount": {
            "type": "integer"
          },
          "recordCount": {
            "type": "integer"
          },
          "errorCount": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ImportBatchPageResponse": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ImportBatch"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageMetadata"
          }
        }
      },
      "ImportSessionPageResponse": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ImportSession"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageMetadata"
          }
        }
      },
      "ImportRecord": {
        "type": "object",
        "required": [
          "id",
          "sessionId",
          "rowIndex",
          "payload"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "sessionId": {
            "type": "string"
          },
          "rowIndex": {
            "type": "integer"
          },
          "payload": {
            "type": "string"
          },
          "validationErrors": {
            "type": "string"
          }
        }
      },
      "ConfirmImportRequest": {
        "type": "object",
        "properties": {
          "acknowledgeOpeningBalanceAdjustment": {
            "type": "boolean",
            "default": false,
            "description": "Set true only after reviewing `pendingOpeningBalanceAdjustment` when the importer would post a ledger bridge before imported rows."
          }
        }
      },
      "PendingOpeningBalanceAdjustmentResponse": {
        "type": "object",
        "required": [
          "adjustmentAmountMinor",
          "currency",
          "ledgerBalanceMinor",
          "statementOpeningBalanceMinor"
        ],
        "properties": {
          "adjustmentAmountMinor": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string"
          },
          "ledgerBalanceMinor": {
            "type": "integer",
            "format": "int64"
          },
          "statementOpeningBalanceMinor": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ImportSessionDetailResponse": {
        "type": "object",
        "required": [
          "session",
          "records"
        ],
        "properties": {
          "session": {
            "$ref": "#/components/schemas/ImportSession"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ImportRecord"
            }
          },
          "pendingOpeningBalanceAdjustment": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/PendingOpeningBalanceAdjustmentResponse"
              }
            ]
          }
        }
      },
      "ImportBatchDetailResponse": {
        "type": "object",
        "required": [
          "batch",
          "items"
        ],
        "properties": {
          "batch": {
            "$ref": "#/components/schemas/ImportBatch"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkImportPreviewItem"
            }
          }
        }
      },
      "BulkImportPreviewResponse": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkImportPreviewItem"
            }
          }
        }
      },
      "BulkImportPreviewItem": {
        "type": "object",
        "required": [
          "fileName"
        ],
        "properties": {
          "fileName": {
            "type": "string"
          },
          "detail": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/ImportSessionDetailResponse"
              }
            ]
          },
          "error": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/ValidationError"
              }
            ]
          }
        }
      },
      "ImportTablePreviewResponse": {
        "type": "object",
        "required": [
          "columns",
          "rows",
          "errors"
        ],
        "properties": {
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              }
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            }
          },
          "tables": {
            "type": "array",
            "description": "Optional detected source table regions. PDF previews use this to show page-level table focus and sample rows.",
            "items": {
              "$ref": "#/components/schemas/ImportTablePreviewRegion"
            }
          }
        }
      },
      "ImportTablePreviewRegion": {
        "type": "object",
        "required": [
          "page",
          "pageWidth",
          "pageHeight",
          "columns",
          "rows",
          "rowCount",
          "bounds"
        ],
        "properties": {
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "pageWidth": {
            "type": "number",
            "format": "double",
            "description": "Source PDF page width in parser coordinates."
          },
          "pageHeight": {
            "type": "number",
            "format": "double",
            "description": "Source PDF page height in parser coordinates."
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              }
            }
          },
          "rowCount": {
            "type": "integer",
            "minimum": 0
          },
          "bounds": {
            "$ref": "#/components/schemas/ImportTablePreviewBounds"
          }
        }
      },
      "ImportTablePreviewBounds": {
        "type": "object",
        "required": [
          "x",
          "y",
          "width",
          "height"
        ],
        "properties": {
          "x": {
            "type": "number",
            "format": "double"
          },
          "y": {
            "type": "number",
            "format": "double"
          },
          "width": {
            "type": "number",
            "format": "double"
          },
          "height": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "ImportCorrectionRequest": {
        "type": "object",
        "required": [
          "corrections"
        ],
        "properties": {
          "corrections": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "rowId",
                "patch"
              ],
              "properties": {
                "rowId": {
                  "type": "string"
                },
                "patch": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "ValidationError": {
        "type": "object",
        "required": [
          "code",
          "message",
          "field"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable validation code. Import workflows can return IMPORT_FORMAT_MISMATCH when the selected format does not match the uploaded file. PDF commits require statement closing balance on every parsed row (`IMPORT_STATEMENT_BALANCE_MISSING` when the preset cannot populate it). Explicit statement opening rows may require `IMPORT_OPENING_BALANCE_ACK_REQUIRED` until confirm is retried with `acknowledgeOpeningBalanceAdjustment=true`."
          },
          "message": {
            "type": "string"
          },
          "field": {
            "type": "string"
          }
        }
      },
      "Money": {
        "type": "object",
        "required": [
          "amountMinor",
          "currency"
        ],
        "properties": {
          "amountMinor": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string"
          }
        }
      },
      "CategoryScope": {
        "type": "string",
        "enum": [
          "MASTER",
          "USER"
        ]
      },
      "CategoryKind": {
        "type": "string",
        "enum": [
          "INCOME",
          "SPENDING",
          "TRANSFER",
          "GENERAL"
        ]
      },
      "Category": {
        "type": "object",
        "required": [
          "id",
          "scope",
          "name",
          "kind",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string",
            "nullable": true,
            "description": "Owning workspace for USER categories; null for MASTER categories."
          },
          "parentId": {
            "type": "string",
            "nullable": true
          },
          "scope": {
            "$ref": "#/components/schemas/CategoryScope"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/CategoryKind"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CategoryRequest": {
        "type": "object",
        "required": [
          "name",
          "kind"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "$ref": "#/components/schemas/CategoryKind"
          },
          "parentId": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CategoryPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "$ref": "#/components/schemas/CategoryKind"
          },
          "parentId": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Transaction": {
        "type": "object",
        "required": [
          "id",
          "accountId",
          "postedAt",
          "description",
          "amount",
          "category"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "accountId": {
            "type": "string"
          },
          "postedAt": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string"
          },
          "merchant": {
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "category": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "MANUAL",
              "IMPORT_CSV",
              "IMPORT_PDF",
              "IMPORT_EXCEL",
              "API_INGESTION",
              "ENRICHED"
            ]
          },
          "notes": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "balanceAfter": {
            "description": "List reads only: account running balance in this row's amount currency after this\ntransaction, using posted date, creation time, then id order. Omitted if not materialized\n(for example, non-paged tests).\n",
            "nullable": true,
            "$ref": "#/components/schemas/Money"
          },
          "interAccountTransfer": {
            "description": "When set, this row is linked to another transaction as an inter-account transfer. Both legs are omitted from income/spending aggregates in insights. Peer details are only populated on transaction detail responses.\n",
            "nullable": true,
            "$ref": "#/components/schemas/InterAccountTransfer"
          }
        }
      },
      "InterAccountLinkCandidate": {
        "type": "object",
        "required": [
          "outgoing",
          "incoming"
        ],
        "properties": {
          "outgoing": {
            "description": "Outflow leg (negative amount) for the proposed link.",
            "$ref": "#/components/schemas/Transaction"
          },
          "incoming": {
            "description": "Inflow leg (positive amount) on another account.",
            "$ref": "#/components/schemas/Transaction"
          }
        }
      },
      "InterAccountTransfer": {
        "type": "object",
        "required": [
          "linkId",
          "peerTransactionId"
        ],
        "properties": {
          "linkId": {
            "type": "string"
          },
          "peerTransactionId": {
            "type": "string"
          },
          "peerAccountId": {
            "type": "string",
            "nullable": true
          },
          "peerAccountName": {
            "type": "string",
            "nullable": true
          },
          "peerPostedAt": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "peerDescription": {
            "type": "string",
            "nullable": true
          },
          "peerAmount": {
            "nullable": true,
            "$ref": "#/components/schemas/Money"
          }
        }
      },
      "CreateInterAccountLinkRequest": {
        "type": "object",
        "required": [
          "peerTransactionId"
        ],
        "properties": {
          "peerTransactionId": {
            "type": "string"
          }
        }
      },
      "InterAccountLinkCreatedResponse": {
        "type": "object",
        "required": [
          "linkId"
        ],
        "properties": {
          "linkId": {
            "type": "string"
          }
        }
      },
      "TransactionPageResponse": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transaction"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageMetadata"
          }
        }
      },
      "CreateTransactionRequest": {
        "type": "object",
        "required": [
          "accountId",
          "postedAt",
          "description",
          "amount",
          "category"
        ],
        "properties": {
          "accountId": {
            "type": "string"
          },
          "postedAt": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string"
          },
          "merchant": {
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "category": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expectedBalanceAfter": {
            "description": "If set, the create fails unless this equals the account running balance in the same\ncurrency immediately after this transaction, given current ledger ordering.\n",
            "nullable": true,
            "$ref": "#/components/schemas/Money"
          }
        }
      },
      "BulkCreateTransactionsRequest": {
        "type": "object",
        "required": [
          "transactions"
        ],
        "properties": {
          "transactions": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "items": {
              "$ref": "#/components/schemas/CreateTransactionRequest"
            }
          }
        }
      },
      "BulkCreateTransactionsResponse": {
        "type": "object",
        "required": [
          "transactions"
        ],
        "properties": {
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transaction"
            }
          }
        }
      },
      "TransactionDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Transaction"
          },
          {
            "type": "object",
            "required": [
              "account",
              "balanceAfter"
            ],
            "properties": {
              "balanceAfter": {
                "$ref": "#/components/schemas/Money",
                "description": "Account running balance in the account currency through this transaction (inclusive), with rows ordered by posted date, then creation time, then id.\n"
              },
              "importSessionId": {
                "type": "string",
                "nullable": true,
                "description": "When this row was created from a committed file import, the import session id (links to Studio import detail for the source document).\n"
              },
              "notes": {
                "type": "string"
              },
              "tags": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "account": {
                "$ref": "#/components/schemas/Account"
              },
              "interAccountTransfer": {
                "nullable": true,
                "$ref": "#/components/schemas/InterAccountTransfer"
              },
              "auditTrail": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "changedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "changedBy": {
                      "type": "string"
                    },
                    "changes": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "UpdateTransactionRequest": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string"
          },
          "postedAt": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string"
          },
          "merchant": {
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "category": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Goal": {
        "type": "object",
        "required": [
          "id",
          "name",
          "targetAmount",
          "currentAmount",
          "targetDate"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "targetAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "currentAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "targetDate": {
            "type": "string",
            "format": "date"
          },
          "progressPercent": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "CreateGoalRequest": {
        "type": "object",
        "required": [
          "name",
          "targetAmount",
          "targetDate"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "targetAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "targetDate": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "UpdateGoalRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "targetAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "currentAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "targetDate": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "Insight": {
        "type": "object",
        "required": [
          "id",
          "month",
          "title",
          "summary",
          "confidence",
          "generatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "month": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "format": "double"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "type": "string",
            "enum": [
              "RULES",
              "OPENAI",
              "ANTHROPIC"
            ]
          }
        }
      },
      "InsightReport": {
        "type": "object",
        "required": [
          "rangeStart",
          "rangeEnd",
          "totals",
          "monthly",
          "categories",
          "patterns"
        ],
        "properties": {
          "rangeStart": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}$"
          },
          "rangeEnd": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}$"
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CashFlowTotal"
            }
          },
          "monthly": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CashFlowPoint"
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CategoryBreakdown"
            }
          },
          "patterns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InsightPattern"
            }
          }
        }
      },
      "CashFlowTotal": {
        "type": "object",
        "required": [
          "currency",
          "incomeMinor",
          "spendingMinor",
          "netMinor",
          "transactionCount"
        ],
        "properties": {
          "currency": {
            "type": "string"
          },
          "incomeMinor": {
            "type": "integer",
            "format": "int64"
          },
          "spendingMinor": {
            "type": "integer",
            "format": "int64"
          },
          "netMinor": {
            "type": "integer",
            "format": "int64"
          },
          "transactionCount": {
            "type": "integer"
          }
        }
      },
      "CashFlowPoint": {
        "type": "object",
        "required": [
          "month",
          "currency",
          "incomeMinor",
          "spendingMinor",
          "netMinor"
        ],
        "properties": {
          "month": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}$"
          },
          "currency": {
            "type": "string"
          },
          "incomeMinor": {
            "type": "integer",
            "format": "int64"
          },
          "spendingMinor": {
            "type": "integer",
            "format": "int64"
          },
          "netMinor": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "CategoryBreakdown": {
        "type": "object",
        "required": [
          "category",
          "currency",
          "amountMinor",
          "transactionCount",
          "direction"
        ],
        "properties": {
          "category": {
            "type": "string"
          },
          "parentCategory": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string"
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64"
          },
          "transactionCount": {
            "type": "integer"
          },
          "direction": {
            "type": "string",
            "enum": [
              "INCOME",
              "SPENDING"
            ]
          }
        }
      },
      "InsightPattern": {
        "type": "object",
        "required": [
          "title",
          "summary",
          "severity"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "INFO",
              "WARNING",
              "SUCCESS"
            ]
          }
        }
      },
      "JobReference": {
        "type": "object",
        "required": [
          "jobId"
        ],
        "properties": {
          "jobId": {
            "type": "string"
          }
        }
      },
      "JobStatus": {
        "type": "object",
        "required": [
          "jobId",
          "workspaceId",
          "type",
          "status",
          "createdAt"
        ],
        "properties": {
          "workspaceId": {
            "type": "string"
          },
          "jobId": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "SCHEDULED",
              "RUNNING",
              "SUCCEEDED",
              "FAILED",
              "DEAD_LETTER",
              "UNCERTAIN"
            ]
          },
          "correlationId": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "NotificationPreference": {
        "type": "object",
        "required": [
          "emailEnabled",
          "smsEnabled",
          "inAppEnabled"
        ],
        "properties": {
          "emailEnabled": {
            "type": "boolean"
          },
          "smsEnabled": {
            "type": "boolean"
          },
          "inAppEnabled": {
            "type": "boolean"
          },
          "locale": {
            "type": "string"
          },
          "quietHours": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string"
              },
              "end": {
                "type": "string"
              }
            }
          }
        }
      },
      "NotificationEvent": {
        "type": "object",
        "required": [
          "id",
          "channel",
          "title",
          "body",
          "sentAt",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "IN_APP",
              "EMAIL",
              "SMS"
            ]
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "sentAt": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "SENT",
              "FAILED"
            ]
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "prefix",
          "scopes",
          "active",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string",
            "description": "The key acts only in this workspace, as its creator, within the creator's role."
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "rotatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiKeyPageResponse": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKey"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageMetadata"
          }
        }
      },
      "ApiKeyCreated": {
        "type": "object",
        "required": [
          "apiKey",
          "secret"
        ],
        "properties": {
          "apiKey": {
            "$ref": "#/components/schemas/ApiKey"
          },
          "secret": {
            "type": "string"
          }
        }
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "required": [
          "name",
          "scopes"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "UpdateApiKeyRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "NotificationTemplate": {
        "type": "object",
        "required": [
          "id",
          "key",
          "locale",
          "channel",
          "subject",
          "body",
          "active"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "locale": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "IN_APP",
              "EMAIL",
              "SMS"
            ]
          },
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "NotificationTemplateUpsert": {
        "type": "object",
        "required": [
          "key",
          "locale",
          "channel",
          "subject",
          "body",
          "active"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "locale": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "IN_APP",
              "EMAIL",
              "SMS"
            ]
          },
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "NotificationTemplatePatch": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "locale": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "IN_APP",
              "EMAIL",
              "SMS"
            ]
          },
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "NotificationRule": {
        "type": "object",
        "required": [
          "id",
          "key",
          "templateKey",
          "scheduleCron",
          "active"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "templateKey": {
            "type": "string"
          },
          "scheduleCron": {
            "type": "string"
          },
          "targetRole": {
            "type": "string",
            "enum": [
              "USER",
              "ADMIN",
              "ANY"
            ]
          },
          "targetCohort": {
            "type": "string"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "IN_APP",
                "EMAIL",
                "SMS"
              ]
            }
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "NotificationRulePatch": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "templateKey": {
            "type": "string"
          },
          "scheduleCron": {
            "type": "string"
          },
          "targetRole": {
            "type": "string",
            "enum": [
              "USER",
              "ADMIN",
              "ANY"
            ]
          },
          "targetCohort": {
            "type": "string"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "IN_APP",
                "EMAIL",
                "SMS"
              ]
            }
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "NotificationRuleUpsert": {
        "type": "object",
        "required": [
          "key",
          "templateKey",
          "scheduleCron",
          "channels",
          "active"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "templateKey": {
            "type": "string"
          },
          "scheduleCron": {
            "type": "string"
          },
          "targetRole": {
            "type": "string",
            "enum": [
              "USER",
              "ADMIN",
              "ANY"
            ]
          },
          "targetCohort": {
            "type": "string"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "IN_APP",
                "EMAIL",
                "SMS"
              ]
            }
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "AdminRowsResponse": {
        "type": "object",
        "required": [
          "table",
          "page",
          "size",
          "totalItems",
          "rows"
        ],
        "properties": {
          "table": {
            "type": "string"
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalItems": {
            "type": "integer",
            "format": "int64"
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "InsertDatabaseRowRequest": {
        "type": "object",
        "required": [
          "columns"
        ],
        "properties": {
          "columns": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "PatchDatabaseRowRequest": {
        "type": "object",
        "required": [
          "match",
          "patch"
        ],
        "properties": {
          "match": {
            "type": "object",
            "additionalProperties": true
          },
          "patch": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "DeleteDatabaseRowRequest": {
        "type": "object",
        "required": [
          "match"
        ],
        "properties": {
          "match": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "ParserPreset": {
        "type": "object",
        "required": [
          "id",
          "key",
          "format",
          "configBlob",
          "active"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV",
              "PDF",
              "EXCEL"
            ]
          },
          "configBlob": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "ParserPresetUpsert": {
        "type": "object",
        "required": [
          "key",
          "format",
          "configBlob",
          "active"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV",
              "PDF",
              "EXCEL"
            ]
          },
          "configBlob": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "ParserPresetPatch": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV",
              "PDF",
              "EXCEL"
            ]
          },
          "configBlob": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "FxRate": {
        "type": "object",
        "required": [
          "base",
          "quote",
          "rate",
          "asOf"
        ],
        "properties": {
          "base": {
            "type": "string"
          },
          "quote": {
            "type": "string"
          },
          "rate": {
            "type": "number",
            "format": "double"
          },
          "asOf": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SorDocument": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "sha256",
          "size",
          "contentType"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "sha256": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "size": {
            "type": "integer"
          },
          "contentType": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        }
      },
      "SorBillTax": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "amount"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50
          },
          "amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          }
        }
      },
      "SorBillLine": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "description",
          "quantity",
          "unit",
          "unitPrice",
          "discount",
          "net",
          "taxComponents",
          "sourcePage",
          "sourceRow"
        ],
        "properties": {
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "quantity": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "unit": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30
          },
          "unitPrice": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "discount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "net": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "taxComponents": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/SorBillTax"
            }
          },
          "sourcePage": {
            "type": "integer",
            "minimum": 1
          },
          "sourceRow": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "SorBillContent": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "documentId",
          "documentType",
          "currency",
          "issuedAt",
          "merchant",
          "subtotal",
          "discount",
          "tax",
          "total",
          "lines"
        ],
        "properties": {
          "documentId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "documentType": {
            "type": "string",
            "enum": [
              "BILL",
              "CREDIT_NOTE"
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "INR",
              "USD",
              "EUR",
              "GBP",
              "JPY",
              "KWD"
            ]
          },
          "issuedAt": {
            "type": "string",
            "format": "date"
          },
          "merchant": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "subtotal": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "discount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "tax": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "total": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
            "maxLength": 30
          },
          "lines": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "items": {
              "$ref": "#/components/schemas/SorBillLine"
            }
          }
        }
      },
      "SorBillRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "content"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "content": {
            "$ref": "#/components/schemas/SorBillContent"
          }
        }
      },
      "SorBill": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "content"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "COMMITTED"
            ]
          },
          "content": {
            "$ref": "#/components/schemas/SorBillContent"
          }
        }
      },
      "SorClassificationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "transactionId",
          "categoryId",
          "expectedCategory",
          "ruleVersion",
          "reason"
        ],
        "properties": {
          "transactionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "categoryId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "expectedCategory": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "ruleVersion": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "SorClassification": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "transactionId",
          "originalCategory",
          "proposedCategory",
          "status",
          "ruleVersion",
          "reason"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "transactionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "originalCategory": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "proposedCategory": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "status": {
            "type": "string",
            "enum": [
              "PROPOSED",
              "ACCEPTED",
              "REVERTED"
            ]
          },
          "ruleVersion": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "SorStatementRow": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "postedAt",
          "description",
          "amount",
          "balanceAfter",
          "sourcePage",
          "sourceRow"
        ],
        "properties": {
          "postedAt": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "amount": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "balanceAfter": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "sourcePage": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000
          },
          "sourceRow": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000
          }
        }
      },
      "SorStatementContent": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "documentId",
          "accountId",
          "currency",
          "periodStart",
          "periodEnd",
          "openingBalance",
          "closingBalance",
          "totalCredits",
          "totalDebits",
          "rows"
        ],
        "properties": {
          "documentId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "accountId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "currency": {
            "type": "string",
            "enum": [
              "INR",
              "USD",
              "EUR",
              "GBP",
              "JPY",
              "KWD"
            ]
          },
          "periodStart": {
            "type": "string",
            "format": "date"
          },
          "periodEnd": {
            "type": "string",
            "format": "date"
          },
          "openingBalance": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "closingBalance": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "totalCredits": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "totalDebits": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "rows": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/SorStatementRow"
            }
          }
        }
      },
      "SorStatementRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "content"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "content": {
            "$ref": "#/components/schemas/SorStatementContent"
          }
        }
      },
      "SorStatement": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "payloadHash",
          "ledgerFingerprint",
          "duplicateCandidates",
          "content"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "COMMITTED",
              "DISCARDED"
            ]
          },
          "payloadHash": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "ledgerFingerprint": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "duplicateCandidates": {
            "type": "integer"
          },
          "content": {
            "$ref": "#/components/schemas/SorStatementContent"
          }
        }
      },
      "SorStatementCommit": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "expectedPayloadHash",
          "acknowledgeDuplicateCandidates"
        ],
        "properties": {
          "expectedPayloadHash": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "acknowledgeDuplicateCandidates": {
            "type": "boolean"
          }
        }
      },
      "SorPositionRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "kind",
          "label",
          "ownershipShare",
          "effectiveDate",
          "sourceReference"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "kind": {
            "type": "string",
            "enum": [
              "ASSET",
              "LIABILITY"
            ]
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "ownershipShare": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "SorPosition": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "kind",
          "label",
          "ownershipShare",
          "effectiveDate",
          "sourceReference",
          "recordedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "kind": {
            "type": "string",
            "enum": [
              "ASSET",
              "LIABILITY"
            ]
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "ownershipShare": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SorValuationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "positionId",
          "currency",
          "value",
          "effectiveDate",
          "sourceReference"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "positionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "currency": {
            "type": "string",
            "minLength": 1,
            "maxLength": 3
          },
          "value": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "SorValuation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "positionId",
          "currency",
          "value",
          "effectiveDate",
          "sourceReference",
          "recordedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "positionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "currency": {
            "type": "string",
            "minLength": 1,
            "maxLength": 3
          },
          "value": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "effectiveDate": {
            "type": "string",
            "format": "date"
          },
          "sourceReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SorNetWorth": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "asOf",
          "knowledgeCutoff",
          "totalsByCurrency",
          "missingPositionIds",
          "stalePositionIds",
          "complete",
          "inventoryCount",
          "dataVersion",
          "evidence"
        ],
        "properties": {
          "asOf": {
            "type": "string",
            "format": "date"
          },
          "knowledgeCutoff": {
            "type": "string",
            "format": "date-time"
          },
          "totalsByCurrency": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "missingPositionIds": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "stalePositionIds": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "complete": {
            "type": "boolean"
          },
          "inventoryCount": {
            "type": "integer"
          },
          "dataVersion": {
            "type": "integer",
            "format": "int64"
          },
          "evidence": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SorValuation"
            }
          }
        }
      },
      "SorAllocationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "billId",
          "transactionId",
          "amount",
          "originalBillId"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "billId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "transactionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "amount": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "originalBillId": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SorAllocation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "billId",
          "transactionId",
          "amountMinor",
          "currency",
          "status",
          "originalBillId"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "billId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "transactionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "amountMinor": {
            "type": "string"
          },
          "currency": {
            "type": "string",
            "minLength": 1,
            "maxLength": 3
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "REVERSED"
            ]
          },
          "originalBillId": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SorSettlement": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "billId",
          "currency",
          "allocatedMinor",
          "unallocatedDocumentMinor",
          "linkedRefundMinor",
          "allocations"
        ],
        "properties": {
          "billId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "currency": {
            "type": "string",
            "minLength": 1,
            "maxLength": 3
          },
          "allocatedMinor": {
            "type": "string"
          },
          "unallocatedDocumentMinor": {
            "type": "string"
          },
          "linkedRefundMinor": {
            "type": "string"
          },
          "allocations": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/SorAllocation"
            }
          }
        }
      },
      "SorPositionPage": {
        "type": "object",
        "required": [
          "items",
          "nextCursor"
        ],
        "properties": {
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/SorPosition"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        }
      }
    }
  }
}
