{
  "openapi": "3.0.3",
  "info": {
    "title": "Finta API v2",
    "version": "2.0.0",
    "description": "DB-backed Finta API for users with storage mode enabled. Requires an API key and active subscription.\n\n## Rate limits\n\nRate limits are enforced per user (shared across the REST API and MCP) based on subscription plan:\n\n| Plan | Per minute | Per day |\n| --- | --- | --- |\n| Standard | 10 requests | 500 requests |\n| Pro | 30 requests | 2,000 requests |\n\nWhen a limit is exceeded, the API returns HTTP 429 with `error.code` `RATE_LIMITED` and a human-readable `message`. A `Retry-After` response header is included with the number of seconds until the window resets."
  },
  "servers": [
    {
      "url": "https://api.finta.io/v2",
      "description": "Production server"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "summary": "Health Check",
        "description": "Returns API health status. Public endpoint; does not require authentication.",
        "operationId": "getHealthV2",
        "tags": [
          "Health"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "503": {
            "description": "Critical dependency unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/bank-connections": {
      "get": {
        "summary": "List bank connections",
        "description": "Returns bank connections from durable Finta data only. Does not call live providers.",
        "operationId": "listBankConnectionsV2",
        "tags": [
          "Bank Connections"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "all",
                "disabled"
              ],
              "default": "active"
            },
            "description": "Filter by connection lifecycle. `active` (default) returns non-disabled connections."
          }
        ],
        "responses": {
          "200": {
            "description": "Bank connections for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankConnectionsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "summary": "Current API user",
        "description": "Returns the authenticated user. Useful for verifying API keys, storage mode, and integration setup.",
        "operationId": "getMeV2",
        "tags": [
          "Me"
        ],
        "responses": {
          "200": {
            "description": "Authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/accounts": {
      "get": {
        "summary": "List accounts",
        "description": "Returns bank accounts from durable Finta data only. Does not call live providers.",
        "operationId": "listAccountsV2",
        "tags": [
          "Accounts"
        ],
        "parameters": [
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank connection ID"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "closed",
                "disconnected",
                "all"
              ],
              "default": "active"
            },
            "description": "Filter by account lifecycle. `active` (default) returns open accounts on non-disabled connections."
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by account type"
          }
        ],
        "responses": {
          "200": {
            "description": "Accounts for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a manual account",
        "description": "Create a manual (non-synced) account the user tracks by hand, including liability accounts (credit, student, mortgage). Only manual accounts can be created.",
        "operationId": "createAccountV2",
        "tags": [
          "Accounts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualAccountCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/accounts/balance-history": {
      "get": {
        "summary": "List balance history",
        "description": "Returns stored daily balance snapshots across accounts. Supports cursor pagination.",
        "operationId": "listBalanceHistoryV2",
        "tags": [
          "Accounts"
        ],
        "parameters": [
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank connection ID"
          },
          {
            "name": "bankAccountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank account ID"
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start date (YYYY-MM-DD)"
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end date (YYYY-MM-DD)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque pagination cursor from a previous response"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 50
            },
            "description": "Page size (default 50, max 250)"
          }
        ],
        "responses": {
          "200": {
            "description": "Balance history entries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceHistoryListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters or cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/accounts/{accountId}": {
      "get": {
        "summary": "Get account",
        "description": "Returns a single bank account by Finta account ID.",
        "operationId": "getAccountV2",
        "tags": [
          "Accounts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Finta bank account ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Account details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Account not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a manual account",
        "description": "Update a manual account's name, type, currency, mask, balance, or liability data. Only manual accounts can be updated; bank-synced accounts are read-only. Updating the balance records a balance-history snapshot for today.",
        "operationId": "updateAccountV2",
        "tags": [
          "Accounts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Finta bank account ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualAccountUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or non-manual account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Account not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a manual account",
        "description": "Soft-close a manual account. Only manual accounts can be deleted; the account moves to `closed` status and keeps its transactions and balance history.",
        "operationId": "deleteAccountV2",
        "tags": [
          "Accounts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Finta bank account ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Account closed"
          },
          "400": {
            "description": "Non-manual account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Account not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/accounts/{accountId}/balance-history": {
      "get": {
        "summary": "List account balance history",
        "description": "Returns stored daily balance snapshots for a single account. Supports cursor pagination.",
        "operationId": "listAccountBalanceHistoryV2",
        "tags": [
          "Accounts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Finta bank account ID"
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start date (YYYY-MM-DD)"
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end date (YYYY-MM-DD)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque pagination cursor from a previous response"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 50
            },
            "description": "Page size (default 50, max 250)"
          }
        ],
        "responses": {
          "200": {
            "description": "Balance history entries for the account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceHistoryListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters or cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Account not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/securities": {
      "get": {
        "summary": "List securities",
        "description": "Returns securities referenced by the authenticated user holdings or investment transactions. Does not call live providers.",
        "operationId": "listSecuritiesV2",
        "tags": [
          "Investments"
        ],
        "parameters": [
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank connection ID"
          },
          {
            "name": "bankAccountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank account ID"
          },
          {
            "name": "securityId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by Finta security ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Securities for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecuritiesListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/holdings": {
      "get": {
        "summary": "List holdings",
        "description": "Returns stored investment holdings from durable Finta data only. Does not call live providers.",
        "operationId": "listHoldingsV2",
        "tags": [
          "Investments"
        ],
        "parameters": [
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank connection ID"
          },
          {
            "name": "bankAccountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank account ID"
          },
          {
            "name": "securityId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by Finta security ID"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "sold",
                "all"
              ],
              "default": "active"
            },
            "description": "Filter by holding lifecycle. `active` (default) excludes sold positions."
          }
        ],
        "responses": {
          "200": {
            "description": "Holdings for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HoldingsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/investment-transactions": {
      "get": {
        "summary": "List investment transactions",
        "description": "Returns stored investment transactions from durable Finta data only. Supports cursor pagination.",
        "operationId": "listInvestmentTransactionsV2",
        "tags": [
          "Investments"
        ],
        "parameters": [
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank connection ID"
          },
          {
            "name": "bankAccountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank account ID"
          },
          {
            "name": "securityId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by Finta security ID"
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start date (YYYY-MM-DD)"
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end date (YYYY-MM-DD)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque pagination cursor from a previous response"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 50
            },
            "description": "Page size (default 50, max 250)"
          }
        ],
        "responses": {
          "200": {
            "description": "Investment transactions for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvestmentTransactionsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters or cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/transactions": {
      "get": {
        "summary": "List transactions",
        "description": "Returns stored transactions from durable Finta data only. Supports cursor pagination. Deleted transactions are excluded by default.",
        "operationId": "listTransactionsV2",
        "tags": [
          "Transactions"
        ],
        "parameters": [
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank connection ID"
          },
          {
            "name": "bankAccountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by bank account ID"
          },
          {
            "name": "categoryId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by category ID"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "posted",
                "deleted",
                "all"
              ],
              "default": "posted"
            },
            "description": "Transaction status filter (default: posted)"
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start date on posted_date (YYYY-MM-DD)"
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end date on posted_date (YYYY-MM-DD)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque pagination cursor from a previous response"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 50
            },
            "description": "Page size (default 50, max 250)"
          },
          {
            "name": "includeHidden",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Include transactions hidden by a rule. Defaults to false."
          }
        ],
        "responses": {
          "200": {
            "description": "Transactions for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters or cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/categories": {
      "get": {
        "summary": "List categories",
        "description": "Returns stored transaction categories from durable Finta data only.",
        "operationId": "listCategoriesV2",
        "tags": [
          "Categories"
        ],
        "parameters": [
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "plaid",
                "go_cardless",
                "stripe",
                "mercury"
              ]
            },
            "description": "Filter by data provider"
          },
          {
            "name": "bankConnectionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to categories used by transactions on this bank connection"
          }
        ],
        "responses": {
          "200": {
            "description": "Categories for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoriesListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a category",
        "description": "Create a new manual category.",
        "operationId": "createCategoryV2",
        "tags": [
          "Categories"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategorySummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/transactions/{id}": {
      "patch": {
        "summary": "Update a transaction",
        "description": "Update fields on a single transaction. Currently supports setting or clearing categoryId.",
        "operationId": "updateTransactionV2",
        "tags": [
          "Transactions"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Transaction UUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated transaction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionSummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Transaction or category not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/transactions/batch": {
      "post": {
        "summary": "Batch update transactions",
        "description": "Update multiple transactions at once (max 250). Currently supports setting or clearing categoryId per transaction.",
        "operationId": "batchUpdateTransactionsV2",
        "tags": [
          "Transactions"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionBatchUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Number of transactions updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchUpdateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "One or more category IDs not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/categories/batch": {
      "post": {
        "summary": "Batch update categories",
        "description": "Update multiple categories at once (max 250). Name, group, and description are editable on any category except Mercury's, which is read-only. Unknown or read-only IDs are skipped.",
        "operationId": "batchUpdateCategoriesV2",
        "tags": [
          "Categories"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryBatchUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Number of categories updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchUpdateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/categories/{id}": {
      "patch": {
        "summary": "Update a category",
        "description": "Update a category's name, group, or description. All three are editable on any category except Mercury's, which is read-only. Edits to a Plaid category persist across future syncs.",
        "operationId": "updateCategoryV2",
        "tags": [
          "Categories"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Category UUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategorySummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, or a read-only (Mercury) category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Category not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a category",
        "description": "Delete a manual category. Transactions assigned to this category will become uncategorized.",
        "operationId": "deleteCategoryV2",
        "tags": [
          "Categories"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Category UUID"
          }
        ],
        "responses": {
          "204": {
            "description": "Category deleted"
          },
          "400": {
            "description": "Non-manual category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Category not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/category-groups": {
      "get": {
        "summary": "List category groups",
        "description": "Returns the authenticated user's category groups in display order (sortOrder first, then name). Cursor-paginated.",
        "operationId": "listCategoryGroupsV2",
        "tags": [
          "Category Groups"
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque pagination cursor from a previous response"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 50
            },
            "description": "Page size (1–250, default 50)"
          }
        ],
        "responses": {
          "200": {
            "description": "Category groups for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryGroupsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters or cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a category group",
        "description": "Create a category group. Names are normalized (trimmed, internal whitespace collapsed) and must be unique per user, compared case-insensitively.",
        "operationId": "createCategoryGroupV2",
        "tags": [
          "Category Groups"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryGroupCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created category group",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryGroup"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, or a group with this name already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/category-groups/{id}": {
      "patch": {
        "summary": "Update a category group",
        "description": "Rename a category group or change its sort order. Renaming also updates the `group` name on every category in the group.",
        "operationId": "updateCategoryGroupV2",
        "tags": [
          "Category Groups"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Category group UUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryGroupUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated category group",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryGroup"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, or a group with this name already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Category group not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a category group",
        "description": "Delete a category group. Categories in the group are kept and become ungrouped (their `categoryGroupId` and `group` are cleared).",
        "operationId": "deleteCategoryGroupV2",
        "tags": [
          "Category Groups"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Category group UUID"
          }
        ],
        "responses": {
          "204": {
            "description": "Category group deleted"
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Category group not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/rules": {
      "get": {
        "summary": "List transaction rules",
        "description": "Returns the authenticated user's transaction rules. Active rules are returned by default.",
        "operationId": "listRulesV2",
        "tags": [
          "Rules"
        ],
        "parameters": [
          {
            "name": "includeArchived",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Include archived rules in the response (default false)"
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction rules for the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRulesListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a transaction rule",
        "description": "Create a new transaction rule that auto-categorizes or hides stored transactions.",
        "operationId": "createRuleV2",
        "tags": [
          "Rules"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleCreateBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created transaction rule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRule"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/rules/run": {
      "post": {
        "summary": "Run transaction rules",
        "description": "Run transaction rules over stored transactions. Omit ruleIds to run all active rules.",
        "operationId": "runRulesV2",
        "tags": [
          "Rules"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleRunBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result of running the rules",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleRunResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/rules/{ruleId}": {
      "patch": {
        "summary": "Update a transaction rule",
        "description": "Update a transaction rule's conditions, outcomes, or priority. At least one field must be provided.",
        "operationId": "updateRuleV2",
        "tags": [
          "Rules"
        ],
        "parameters": [
          {
            "name": "ruleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Transaction rule UUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated transaction rule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRule"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Rule not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Archive a transaction rule",
        "description": "Archive a transaction rule. Archived rules no longer run but remain retrievable with includeArchived.",
        "operationId": "deleteRuleV2",
        "tags": [
          "Rules"
        ],
        "parameters": [
          {
            "name": "ruleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Transaction rule UUID"
          }
        ],
        "responses": {
          "204": {
            "description": "Rule archived"
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "404": {
            "description": "Rule not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedResponse"
          },
          "403": {
            "description": "Storage mode required or subscription inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key",
        "description": "Finta API key from the dashboard (Bearer token)."
      }
    },
    "responses": {
      "RateLimitedResponse": {
        "description": "Rate limit exceeded",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the rate-limit window resets",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "RATE_LIMITED",
                "message": "Per-minute rate limit exceeded (10 requests/min on Standard plan)."
              }
            }
          }
        }
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "status",
              "timestamp"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "ok",
                  "degraded"
                ]
              },
              "timestamp": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "UnauthorizedResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "example": "Missing or invalid Authorization header"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "STORAGE_MODE_REQUIRED"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "MeResponse": {
        "type": "object",
        "required": [
          "userId",
          "email",
          "storageMode"
        ],
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "storageMode": {
            "type": "boolean",
            "description": "Whether storage mode is enabled for this user"
          }
        }
      },
      "BankConnectionSummary": {
        "type": "object",
        "required": [
          "id",
          "provider",
          "institutionName",
          "institutionLogoUrl",
          "status",
          "lastSyncedAt",
          "lastProviderErrorCode",
          "lastProviderErrorMessage",
          "reconnectUrl"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "provider": {
            "type": "string",
            "example": "plaid"
          },
          "institutionName": {
            "type": "string",
            "nullable": true
          },
          "institutionLogoUrl": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "error",
              "disabled"
            ]
          },
          "lastSyncedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last time this bank connection synced to destinations"
          },
          "lastProviderErrorCode": {
            "type": "string",
            "nullable": true,
            "example": "ITEM_LOGIN_REQUIRED"
          },
          "lastProviderErrorMessage": {
            "type": "string",
            "nullable": true
          },
          "reconnectUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        }
      },
      "BankConnectionsListResponse": {
        "type": "object",
        "required": [
          "bankConnections"
        ],
        "properties": {
          "bankConnections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankConnectionSummary"
            }
          }
        }
      },
      "AccountSummary": {
        "type": "object",
        "required": [
          "id",
          "providerAccountId",
          "bankConnectionId",
          "bankConnectionStatus",
          "provider",
          "institutionName",
          "name",
          "mask",
          "type",
          "subtype",
          "currency",
          "currentBalance",
          "availableBalance",
          "balanceAsOf",
          "status",
          "closedAt",
          "liability"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "providerAccountId": {
            "type": "string"
          },
          "bankConnectionId": {
            "type": "string",
            "format": "uuid"
          },
          "bankConnectionStatus": {
            "type": "string",
            "enum": [
              "active",
              "error",
              "disabled"
            ]
          },
          "provider": {
            "type": "string",
            "example": "plaid"
          },
          "institutionName": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string"
          },
          "mask": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "subtype": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "currentBalance": {
            "type": "number",
            "nullable": true
          },
          "availableBalance": {
            "type": "number",
            "nullable": true
          },
          "balanceAsOf": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "closed",
              "disconnected"
            ]
          },
          "closedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "liability": {
            "$ref": "#/components/schemas/AccountLiability"
          }
        }
      },
      "AccountLiability": {
        "type": "object",
        "nullable": true,
        "description": "Liability detail for `credit`, `student`, or `mortgage` accounts; `null` for non-liability accounts. Fields not relevant to the liability type are `null`. The same shape is accepted when creating or updating a manual account.",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "credit",
              "student",
              "mortgage"
            ]
          },
          "minimumPaymentAmount": {
            "type": "number",
            "nullable": true
          },
          "nextPaymentDueDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "lastPaymentAmount": {
            "type": "number",
            "nullable": true
          },
          "lastPaymentDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "interestRate": {
            "type": "number",
            "nullable": true
          },
          "isOverdue": {
            "type": "boolean",
            "nullable": true
          },
          "lastStatementBalance": {
            "type": "number",
            "nullable": true,
            "description": "Credit accounts only."
          },
          "aprs": {
            "type": "array",
            "description": "Credit accounts only.",
            "items": {
              "type": "object",
              "required": [
                "aprType",
                "aprPercentage"
              ],
              "properties": {
                "aprType": {
                  "type": "string"
                },
                "aprPercentage": {
                  "type": "number"
                },
                "balanceSubjectToApr": {
                  "type": "number",
                  "nullable": true
                },
                "interestChargeAmount": {
                  "type": "number",
                  "nullable": true
                }
              }
            }
          },
          "loanName": {
            "type": "string",
            "nullable": true,
            "description": "Student accounts only."
          },
          "loanStatus": {
            "type": "object",
            "nullable": true,
            "description": "Student accounts only.",
            "properties": {
              "type": {
                "type": "string",
                "nullable": true
              },
              "endDate": {
                "type": "string",
                "format": "date",
                "nullable": true
              }
            }
          },
          "repaymentPlan": {
            "type": "object",
            "nullable": true,
            "description": "Student accounts only.",
            "properties": {
              "type": {
                "type": "string",
                "nullable": true
              },
              "description": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "pslfStatus": {
            "type": "object",
            "nullable": true,
            "description": "Student accounts only.",
            "properties": {
              "paymentsRemaining": {
                "type": "number",
                "nullable": true
              },
              "paymentsMade": {
                "type": "number",
                "nullable": true
              },
              "estimatedEligibilityDate": {
                "type": "string",
                "format": "date",
                "nullable": true
              }
            }
          },
          "originationDate": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Student and mortgage accounts."
          },
          "originationPrincipalAmount": {
            "type": "number",
            "nullable": true,
            "description": "Student and mortgage accounts."
          },
          "expectedPayoffDate": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Student accounts only."
          },
          "outstandingInterestAmount": {
            "type": "number",
            "nullable": true,
            "description": "Student accounts only."
          },
          "ytdInterestPaid": {
            "type": "number",
            "nullable": true,
            "description": "Student and mortgage accounts."
          },
          "ytdPrincipalPaid": {
            "type": "number",
            "nullable": true,
            "description": "Student and mortgage accounts."
          },
          "interestRateType": {
            "type": "string",
            "enum": [
              "fixed",
              "variable"
            ],
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "nextMonthlyPayment": {
            "type": "number",
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "escrowBalance": {
            "type": "number",
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "hasPmi": {
            "type": "boolean",
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "hasPrepaymentPenalty": {
            "type": "boolean",
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "propertyAddress": {
            "type": "object",
            "nullable": true,
            "description": "Mortgage accounts only.",
            "properties": {
              "street": {
                "type": "string",
                "nullable": true
              },
              "city": {
                "type": "string",
                "nullable": true
              },
              "region": {
                "type": "string",
                "nullable": true
              },
              "postalCode": {
                "type": "string",
                "nullable": true
              },
              "country": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "loanTypeDescription": {
            "type": "string",
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "maturityDate": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Mortgage accounts only."
          },
          "pastDueAmount": {
            "type": "number",
            "nullable": true,
            "description": "Mortgage accounts only."
          }
        }
      },
      "ManualAccountCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "institutionName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Institution label. Defaults to 'Manual'."
          },
          "type": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "e.g. depository, credit, loan, investment, other"
          },
          "subtype": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "e.g. checking, savings, credit card, mortgage, student"
          },
          "mask": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "currency": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10,
            "description": "ISO currency code, e.g. USD"
          },
          "currentBalance": {
            "type": "number",
            "description": "For liabilities, use a positive number for the amount owed."
          },
          "availableBalance": {
            "type": "number"
          },
          "liability": {
            "$ref": "#/components/schemas/AccountLiability"
          }
        }
      },
      "ManualAccountUpdateRequest": {
        "type": "object",
        "description": "At least one field must be provided. Pass `null` to clear a nullable field.",
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "type": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "nullable": true
          },
          "subtype": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "nullable": true
          },
          "mask": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "nullable": true
          },
          "currency": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10
          },
          "currentBalance": {
            "type": "number",
            "nullable": true
          },
          "availableBalance": {
            "type": "number",
            "nullable": true
          },
          "liability": {
            "$ref": "#/components/schemas/AccountLiability"
          }
        }
      },
      "AccountsListResponse": {
        "type": "object",
        "required": [
          "accounts"
        ],
        "properties": {
          "accounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountSummary"
            }
          }
        }
      },
      "AccountResponse": {
        "type": "object",
        "required": [
          "account"
        ],
        "properties": {
          "account": {
            "$ref": "#/components/schemas/AccountSummary"
          }
        }
      },
      "BalanceHistoryEntry": {
        "type": "object",
        "required": [
          "id",
          "bankAccountId",
          "accountName",
          "date",
          "balance",
          "currency"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "bankAccountId": {
            "type": "string",
            "format": "uuid"
          },
          "accountName": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "balance": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "PageInfo": {
        "type": "object",
        "required": [
          "nextCursor",
          "hasMore"
        ],
        "properties": {
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "hasMore": {
            "type": "boolean"
          }
        }
      },
      "BalanceHistoryListResponse": {
        "type": "object",
        "required": [
          "balanceHistory",
          "pageInfo"
        ],
        "properties": {
          "balanceHistory": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BalanceHistoryEntry"
            }
          },
          "pageInfo": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "SecurityProviderId": {
        "type": "object",
        "required": [
          "provider",
          "providerId"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "example": "plaid"
          },
          "providerId": {
            "type": "string"
          }
        }
      },
      "SecuritySummary": {
        "type": "object",
        "required": [
          "id",
          "tickerSymbol",
          "name",
          "type",
          "isin",
          "cusip",
          "currency",
          "closePrice",
          "closePriceAsOf",
          "isCashEquivalent",
          "sector",
          "industry",
          "optionContractType",
          "optionExpirationDate",
          "optionStrikePrice",
          "optionUnderlyingTicker",
          "providerIds"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tickerSymbol": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "isin": {
            "type": "string",
            "nullable": true
          },
          "cusip": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "closePrice": {
            "type": "number",
            "nullable": true
          },
          "closePriceAsOf": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "isCashEquivalent": {
            "type": "boolean"
          },
          "sector": {
            "type": "string",
            "nullable": true
          },
          "industry": {
            "type": "string",
            "nullable": true
          },
          "optionContractType": {
            "type": "string",
            "nullable": true
          },
          "optionExpirationDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "optionStrikePrice": {
            "type": "number",
            "nullable": true
          },
          "optionUnderlyingTicker": {
            "type": "string",
            "nullable": true
          },
          "providerIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SecurityProviderId"
            }
          }
        }
      },
      "SecuritiesListResponse": {
        "type": "object",
        "required": [
          "securities"
        ],
        "properties": {
          "securities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SecuritySummary"
            }
          }
        }
      },
      "HoldingSummary": {
        "type": "object",
        "required": [
          "id",
          "bankConnectionId",
          "bankAccountId",
          "securityId",
          "quantity",
          "costBasis",
          "currency",
          "status",
          "soldAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "bankConnectionId": {
            "type": "string",
            "format": "uuid"
          },
          "bankAccountId": {
            "type": "string",
            "format": "uuid"
          },
          "securityId": {
            "type": "string",
            "format": "uuid"
          },
          "quantity": {
            "type": "number"
          },
          "costBasis": {
            "type": "number",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "sold"
            ]
          },
          "soldAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "HoldingsListResponse": {
        "type": "object",
        "required": [
          "holdings"
        ],
        "properties": {
          "holdings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HoldingSummary"
            }
          }
        }
      },
      "InvestmentTransactionSummary": {
        "type": "object",
        "required": [
          "id",
          "bankConnectionId",
          "bankAccountId",
          "securityId",
          "provider",
          "providerId",
          "date",
          "amount",
          "quantity",
          "price",
          "fees",
          "currency",
          "summary",
          "type",
          "subtype"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "bankConnectionId": {
            "type": "string",
            "format": "uuid"
          },
          "bankAccountId": {
            "type": "string",
            "format": "uuid"
          },
          "securityId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "provider": {
            "type": "string",
            "example": "plaid"
          },
          "providerId": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "amount": {
            "type": "number"
          },
          "quantity": {
            "type": "number",
            "nullable": true
          },
          "price": {
            "type": "number",
            "nullable": true
          },
          "fees": {
            "type": "number",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "subtype": {
            "type": "string"
          }
        }
      },
      "InvestmentTransactionsListResponse": {
        "type": "object",
        "required": [
          "investmentTransactions",
          "pageInfo"
        ],
        "properties": {
          "investmentTransactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvestmentTransactionSummary"
            }
          },
          "pageInfo": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "TransactionSummary": {
        "type": "object",
        "required": [
          "id",
          "bankConnectionId",
          "bankAccountId",
          "provider",
          "providerId",
          "status",
          "summary",
          "amount",
          "currency",
          "authorizedDate",
          "postedDate",
          "merchantName",
          "categoryId",
          "fees",
          "feeType",
          "netAmount",
          "subAccount",
          "paymentChannel",
          "checkNumber",
          "originalDescription",
          "source"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "bankConnectionId": {
            "type": "string",
            "format": "uuid"
          },
          "bankAccountId": {
            "type": "string",
            "format": "uuid"
          },
          "provider": {
            "type": "string",
            "example": "plaid"
          },
          "providerId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "posted",
              "deleted"
            ]
          },
          "summary": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "authorizedDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "postedDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "merchantName": {
            "type": "string",
            "nullable": true
          },
          "categoryId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "fees": {
            "type": "number",
            "nullable": true
          },
          "feeType": {
            "type": "string",
            "nullable": true
          },
          "netAmount": {
            "type": "number",
            "nullable": true
          },
          "subAccount": {
            "type": "string",
            "nullable": true
          },
          "paymentChannel": {
            "type": "string",
            "nullable": true
          },
          "checkNumber": {
            "type": "string",
            "nullable": true
          },
          "originalDescription": {
            "type": "string",
            "nullable": true
          },
          "source": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "TransactionsListResponse": {
        "type": "object",
        "required": [
          "transactions",
          "pageInfo"
        ],
        "properties": {
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionSummary"
            }
          },
          "pageInfo": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "CategorySummary": {
        "type": "object",
        "required": [
          "id",
          "provider",
          "providerId",
          "name",
          "group",
          "categoryGroupId",
          "description"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "provider": {
            "type": "string",
            "example": "plaid"
          },
          "providerId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "group": {
            "type": "string",
            "nullable": true,
            "description": "Name of the category group this category belongs to"
          },
          "categoryGroupId": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of the category group this category belongs to (see /category-groups)"
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CategoriesListResponse": {
        "type": "object",
        "required": [
          "categories"
        ],
        "properties": {
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CategorySummary"
            }
          }
        }
      },
      "CategoryCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "group": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Group name. An existing group is reused (case-insensitive match); a new one is created if it does not exist."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "CategoryUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "group": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Group name. An existing group is reused (case-insensitive match); a new one is created if it does not exist."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "nullable": true
          }
        }
      },
      "CategoryBatchUpdateRequest": {
        "type": "object",
        "required": [
          "updates"
        ],
        "properties": {
          "updates": {
            "type": "array",
            "minItems": 1,
            "maxItems": 250,
            "items": {
              "type": "object",
              "required": [
                "id"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "group": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "description": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500,
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "CategoryGroup": {
        "type": "object",
        "required": [
          "id",
          "name",
          "sortOrder"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "nullable": true,
            "description": "Explicit display order. Groups without one sort last, alphabetically."
          }
        }
      },
      "CategoryGroupsListResponse": {
        "type": "object",
        "required": [
          "categoryGroups",
          "pageInfo"
        ],
        "properties": {
          "categoryGroups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CategoryGroup"
            }
          },
          "pageInfo": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "CategoryGroupCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "sortOrder": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000,
            "nullable": true
          }
        }
      },
      "CategoryGroupUpdateRequest": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "sortOrder": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000,
            "nullable": true
          }
        }
      },
      "TransactionUpdateRequest": {
        "type": "object",
        "properties": {
          "categoryId": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Category UUID to assign, or null to remove"
          }
        }
      },
      "TransactionBatchUpdateRequest": {
        "type": "object",
        "required": [
          "updates"
        ],
        "properties": {
          "updates": {
            "type": "array",
            "minItems": 1,
            "maxItems": 250,
            "items": {
              "type": "object",
              "required": [
                "id"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "categoryId": {
                  "type": "string",
                  "format": "uuid",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "BatchUpdateResponse": {
        "type": "object",
        "required": [
          "updated"
        ],
        "properties": {
          "updated": {
            "type": "integer",
            "description": "Number of records updated"
          }
        }
      },
      "TransactionRule": {
        "type": "object",
        "required": [
          "id",
          "conditions",
          "outcomes",
          "priority",
          "createdAt",
          "updatedAt",
          "archivedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "conditions": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "outcomes": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "priority": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "archivedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "TransactionRulesListResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRule"
            }
          }
        }
      },
      "TransactionRuleCreateBody": {
        "type": "object",
        "required": [
          "conditions",
          "outcomes"
        ],
        "properties": {
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Conditions match transactions on Account, Summary, OriginalDescription, MerchantName, Amount, or transactionDay. Each condition is an object describing a field and how to match it."
          },
          "outcomes": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Outcomes applied to matching transactions. Set Category (`{ action: 'updateTransaction', field: 'Category', value: { id, value } }`) or MerchantName, or hide the transaction (`{ action: 'hideTransaction', value: true }`)."
          },
          "priority": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        }
      },
      "TransactionRuleUpdateBody": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Conditions match transactions on Account, Summary, OriginalDescription, MerchantName, Amount, or transactionDay. Each condition is an object describing a field and how to match it."
          },
          "outcomes": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Outcomes applied to matching transactions. Set Category (`{ action: 'updateTransaction', field: 'Category', value: { id, value } }`) or MerchantName, or hide the transaction (`{ action: 'hideTransaction', value: true }`)."
          },
          "priority": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        }
      },
      "TransactionRuleRunBody": {
        "type": "object",
        "properties": {
          "ruleIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Specific rule IDs to run. Omit to run all active rules."
          }
        }
      },
      "TransactionRuleRunResult": {
        "type": "object",
        "required": [
          "scanned",
          "matched",
          "updated"
        ],
        "properties": {
          "scanned": {
            "type": "integer",
            "description": "Number of transactions scanned"
          },
          "matched": {
            "type": "integer",
            "description": "Number of transactions matched by a rule"
          },
          "updated": {
            "type": "integer",
            "description": "Number of transactions updated"
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Me",
      "description": "Authenticated user"
    },
    {
      "name": "Health",
      "description": "Service health"
    },
    {
      "name": "Bank Connections",
      "description": "Bank connection resources"
    },
    {
      "name": "Accounts",
      "description": "Account and balance history resources"
    },
    {
      "name": "Investments",
      "description": "Securities, holdings, and investment transaction resources"
    },
    {
      "name": "Transactions",
      "description": "Transaction resources"
    },
    {
      "name": "Categories",
      "description": "Transaction category resources"
    },
    {
      "name": "Category Groups",
      "description": "Category group resources"
    },
    {
      "name": "Rules",
      "description": "Transaction rule resources"
    }
  ]
}
