{ "components": { "schemas": { "AccountBalance": { "properties": { "account_id": { "title": "Account Id", "type": "integer" }, "balance": { "description": "decimal as string", "title": "Balance", "type": "string" }, "balance_rub": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Balance Rub" }, "currency": { "title": "Currency", "type": "string" }, "name": { "title": "Name", "type": "string" }, "role": { "$ref": "#/components/schemas/AccountRole" } }, "required": [ "account_id", "name", "currency", "role", "balance", "balance_rub" ], "title": "AccountBalance", "type": "object" }, "AccountKind": { "enum": [ "zm_cash", "zm_card", "zm_checking", "zm_deposit", "zm_loan", "zm_emoney", "zm_debt", "broker", "manual_asset" ], "title": "AccountKind", "type": "string" }, "AccountOut": { "properties": { "archived": { "title": "Archived", "type": "boolean" }, "balance": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Balance" }, "balance_as_of": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Balance As Of" }, "broker": { "anyOf": [ { "$ref": "#/components/schemas/Broker" }, { "type": "null" } ] }, "credit_limit": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Credit Limit" }, "currency": { "title": "Currency", "type": "string" }, "id": { "title": "Id", "type": "integer" }, "include_in_net_worth": { "title": "Include In Net Worth", "type": "boolean" }, "kind": { "$ref": "#/components/schemas/AccountKind" }, "mirror_of_account_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Mirror Of Account Id" }, "name": { "title": "Name", "type": "string" }, "opened_at": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "Opened At" }, "primary_event_source": { "anyOf": [ { "$ref": "#/components/schemas/EventSource" }, { "type": "null" } ] }, "role": { "$ref": "#/components/schemas/AccountRole" }, "source": { "title": "Source", "type": "string" }, "source_id": { "title": "Source Id", "type": "string" }, "start_balance": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Start Balance" } }, "required": [ "id", "kind", "source", "source_id", "broker", "name", "currency", "role", "include_in_net_worth", "mirror_of_account_id", "primary_event_source", "archived", "opened_at", "balance", "balance_as_of", "start_balance", "credit_limit" ], "title": "AccountOut", "type": "object" }, "AccountPatch": { "additionalProperties": false, "description": "Only the fields the user owns: everything else comes from the source on each sync.\n\nUnset fields are left alone; an explicit `null` clears the column.", "properties": { "include_in_net_worth": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Include In Net Worth" }, "mirror_of_account_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Mirror Of Account Id" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "primary_event_source": { "anyOf": [ { "$ref": "#/components/schemas/EventSource" }, { "type": "null" } ] }, "role": { "anyOf": [ { "$ref": "#/components/schemas/AccountRole" }, { "type": "null" } ] } }, "title": "AccountPatch", "type": "object" }, "AccountRole": { "enum": [ "liquid", "savings", "investment", "debt" ], "title": "AccountRole", "type": "string" }, "Broker": { "enum": [ "tinvest", "sber", "vtb", "other" ], "title": "Broker", "type": "string" }, "CashFlowMonth": { "properties": { "baseline_rub": { "description": "decimal as string", "title": "Baseline Rub", "type": "string" }, "expense_rub": { "description": "decimal as string", "title": "Expense Rub", "type": "string" }, "income_rub": { "description": "decimal as string", "title": "Income Rub", "type": "string" }, "month": { "format": "date", "title": "Month", "type": "string" }, "one_off_rub": { "description": "decimal as string", "title": "One Off Rub", "type": "string" }, "savings_rate": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Savings Rate" }, "savings_transfer_rub": { "description": "decimal as string", "title": "Savings Transfer Rub", "type": "string" }, "txn_count": { "title": "Txn Count", "type": "integer" } }, "required": [ "month", "income_rub", "expense_rub", "baseline_rub", "one_off_rub", "savings_transfer_rub", "savings_rate", "txn_count" ], "title": "CashFlowMonth", "type": "object" }, "CategoryOut": { "description": "Flat list; the client builds the tree from `parent_id` (ZenMoney nests one level).", "properties": { "archived": { "title": "Archived", "type": "boolean" }, "color": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Color" }, "icon": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Icon" }, "id": { "title": "Id", "type": "integer" }, "name": { "title": "Name", "type": "string" }, "parent_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Parent Id" }, "show_income": { "title": "Show Income", "type": "boolean" }, "show_outcome": { "title": "Show Outcome", "type": "boolean" } }, "required": [ "id", "parent_id", "name", "icon", "color", "show_income", "show_outcome", "archived" ], "title": "CategoryOut", "type": "object" }, "DataQualityRow": { "properties": { "check_name": { "title": "Check Name", "type": "string" }, "computed_at": { "format": "date-time", "title": "Computed At", "type": "string" }, "count": { "title": "Count", "type": "integer" }, "detail": { "title": "Detail", "type": "string" }, "id": { "title": "Id", "type": "integer" }, "ref": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Ref" }, "severity": { "title": "Severity", "type": "string" } }, "required": [ "id", "check_name", "severity", "detail", "count", "ref", "computed_at" ], "title": "DataQualityRow", "type": "object" }, "EventSource": { "description": "Which feed is the truth for an account's ledger; others become `shadow` events.", "enum": [ "tinvest_api", "report_sber", "report_vtb", "manual" ], "title": "EventSource", "type": "string" }, "FlowType": { "enum": [ "income", "expense", "internal_transfer", "savings_transfer", "broker_external_flow", "deleted", "other" ], "title": "FlowType", "type": "string" }, "Health": { "properties": { "database": { "title": "Database", "type": "string" }, "status": { "title": "Status", "type": "string" }, "version": { "title": "Version", "type": "string" } }, "required": [ "status", "version", "database" ], "title": "Health", "type": "object" }, "JobStatus": { "enum": [ "queued", "running", "done", "error" ], "title": "JobStatus", "type": "string" }, "LoginRequest": { "properties": { "email": { "format": "email", "title": "Email", "type": "string" }, "password": { "maxLength": 1024, "minLength": 1, "title": "Password", "type": "string" } }, "required": [ "email", "password" ], "title": "LoginRequest", "type": "object" }, "NetWorthBreakdown": { "properties": { "accounts": { "items": { "$ref": "#/components/schemas/AccountBalance" }, "title": "Accounts", "type": "array" }, "by_currency": { "additionalProperties": { "type": "string" }, "title": "By Currency", "type": "object" }, "d": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "D" }, "debt_rub": { "description": "decimal as string", "title": "Debt Rub", "type": "string" }, "investment_rub": { "description": "decimal as string", "title": "Investment Rub", "type": "string" }, "liquid_rub": { "description": "decimal as string", "title": "Liquid Rub", "type": "string" }, "missing_fx_count": { "title": "Missing Fx Count", "type": "integer" }, "savings_rub": { "description": "decimal as string", "title": "Savings Rub", "type": "string" }, "total_rub": { "description": "decimal as string", "title": "Total Rub", "type": "string" } }, "required": [ "d", "total_rub", "liquid_rub", "savings_rub", "investment_rub", "debt_rub", "by_currency", "missing_fx_count", "accounts" ], "title": "NetWorthBreakdown", "type": "object" }, "NetWorthDay": { "properties": { "by_currency": { "additionalProperties": { "type": "string" }, "title": "By Currency", "type": "object" }, "d": { "format": "date", "title": "D", "type": "string" }, "debt_rub": { "description": "decimal as string", "title": "Debt Rub", "type": "string" }, "investment_rub": { "description": "decimal as string", "title": "Investment Rub", "type": "string" }, "liquid_rub": { "description": "decimal as string", "title": "Liquid Rub", "type": "string" }, "missing_fx_count": { "title": "Missing Fx Count", "type": "integer" }, "savings_rub": { "description": "decimal as string", "title": "Savings Rub", "type": "string" }, "total_rub": { "description": "decimal as string", "title": "Total Rub", "type": "string" } }, "required": [ "d", "total_rub", "liquid_rub", "savings_rub", "investment_rub", "debt_rub", "by_currency", "missing_fx_count" ], "title": "NetWorthDay", "type": "object" }, "Problem": { "description": "RFC 7807 error body (application/problem+json)", "properties": { "detail": { "type": "string" }, "errors": { "items": {}, "type": "array" }, "status": { "type": "integer" }, "title": { "type": "string" } }, "required": [ "status", "title" ], "title": "Problem", "type": "object" }, "RefreshLogOut": { "properties": { "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Error" }, "finished_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Finished At" }, "id": { "title": "Id", "type": "integer" }, "started_at": { "format": "date-time", "title": "Started At", "type": "string" }, "trigger": { "title": "Trigger", "type": "string" } }, "required": [ "id", "started_at", "finished_at", "trigger", "error" ], "title": "RefreshLogOut", "type": "object" }, "RefreshRequest": { "properties": { "refresh_token": { "minLength": 1, "title": "Refresh Token", "type": "string" } }, "required": [ "refresh_token" ], "title": "RefreshRequest", "type": "object" }, "RuleCreate": { "additionalProperties": false, "properties": { "enabled": { "default": true, "title": "Enabled", "type": "boolean" }, "kind": { "$ref": "#/components/schemas/RuleKind" }, "match_type": { "$ref": "#/components/schemas/RuleMatchType" }, "note": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Note" }, "pattern": { "maxLength": 512, "minLength": 1, "title": "Pattern", "type": "string" }, "priority": { "default": 100, "title": "Priority", "type": "integer" }, "value": { "anyOf": [ { "maxLength": 512, "type": "string" }, { "type": "null" } ], "title": "Value" } }, "required": [ "kind", "match_type", "pattern" ], "title": "RuleCreate", "type": "object" }, "RuleKind": { "enum": [ "savings", "one_off", "category", "payee", "broker_target", "ignore" ], "title": "RuleKind", "type": "string" }, "RuleMatchType": { "enum": [ "id", "payee", "comment", "category", "mcc", "account" ], "title": "RuleMatchType", "type": "string" }, "RuleOut": { "properties": { "enabled": { "title": "Enabled", "type": "boolean" }, "id": { "title": "Id", "type": "integer" }, "kind": { "$ref": "#/components/schemas/RuleKind" }, "last_matched_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Last Matched At" }, "match_count": { "title": "Match Count", "type": "integer" }, "match_type": { "$ref": "#/components/schemas/RuleMatchType" }, "note": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Note" }, "pattern": { "title": "Pattern", "type": "string" }, "priority": { "title": "Priority", "type": "integer" }, "value": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Value" } }, "required": [ "id", "kind", "match_type", "pattern", "value", "note", "enabled", "priority", "last_matched_at", "match_count" ], "title": "RuleOut", "type": "object" }, "RulePatch": { "additionalProperties": false, "properties": { "enabled": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Enabled" }, "kind": { "anyOf": [ { "$ref": "#/components/schemas/RuleKind" }, { "type": "null" } ] }, "match_type": { "anyOf": [ { "$ref": "#/components/schemas/RuleMatchType" }, { "type": "null" } ] }, "note": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Note" }, "pattern": { "anyOf": [ { "maxLength": 512, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Pattern" }, "priority": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Priority" }, "value": { "anyOf": [ { "maxLength": 512, "type": "string" }, { "type": "null" } ], "title": "Value" } }, "title": "RulePatch", "type": "object" }, "RunStatus": { "enum": [ "running", "ok", "error" ], "title": "RunStatus", "type": "string" }, "RunwayOut": { "properties": { "as_of": { "format": "date", "title": "As Of", "type": "string" }, "avg_baseline_3m_rub": { "description": "decimal as string", "title": "Avg Baseline 3M Rub", "type": "string" }, "liquid_reserve_rub": { "description": "decimal as string", "title": "Liquid Reserve Rub", "type": "string" }, "runway_months": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Runway Months" } }, "required": [ "as_of", "liquid_reserve_rub", "avg_baseline_3m_rub", "runway_months" ], "title": "RunwayOut", "type": "object" }, "SourceStatus": { "properties": { "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Cursor" }, "last_run_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Last Run At" }, "last_run_status": { "anyOf": [ { "$ref": "#/components/schemas/RunStatus" }, { "type": "null" } ] }, "last_success_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Last Success At" }, "queued": { "title": "Queued", "type": "boolean" }, "source": { "title": "Source", "type": "string" } }, "required": [ "source", "cursor", "last_run_at", "last_success_at", "last_run_status", "queued" ], "title": "SourceStatus", "type": "object" }, "SpendingRow": { "properties": { "amount_rub": { "description": "decimal as string", "title": "Amount Rub", "type": "string" }, "category_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Category Id" }, "category_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Category Name" }, "month": { "format": "date", "title": "Month", "type": "string" }, "root_category_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Root Category Id" }, "root_category_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Root Category Name" }, "txn_count": { "title": "Txn Count", "type": "integer" } }, "required": [ "month", "category_id", "category_name", "root_category_id", "root_category_name", "amount_rub", "txn_count" ], "title": "SpendingRow", "type": "object" }, "SyncJobOut": { "properties": { "id": { "format": "uuid", "title": "Id", "type": "string" }, "requested_at": { "format": "date-time", "title": "Requested At", "type": "string" }, "source": { "title": "Source", "type": "string" }, "status": { "$ref": "#/components/schemas/JobStatus" } }, "required": [ "id", "source", "status", "requested_at" ], "title": "SyncJobOut", "type": "object" }, "SyncRunOut": { "properties": { "counts": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Counts" }, "cursor_after": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Cursor After" }, "cursor_before": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Cursor Before" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Error" }, "finished_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Finished At" }, "id": { "format": "uuid", "title": "Id", "type": "string" }, "source": { "title": "Source", "type": "string" }, "started_at": { "format": "date-time", "title": "Started At", "type": "string" }, "status": { "$ref": "#/components/schemas/RunStatus" }, "triggered_by": { "title": "Triggered By", "type": "string" }, "warnings": { "anyOf": [ { "items": {}, "type": "array" }, { "type": "null" } ], "title": "Warnings" } }, "required": [ "id", "source", "status", "triggered_by", "started_at", "finished_at", "cursor_before", "cursor_after", "counts", "warnings", "error" ], "title": "SyncRunOut", "type": "object" }, "TokenPair": { "properties": { "access_token": { "title": "Access Token", "type": "string" }, "expires_in": { "title": "Expires In", "type": "integer" }, "refresh_token": { "title": "Refresh Token", "type": "string" }, "token_type": { "default": "bearer", "title": "Token Type", "type": "string" } }, "required": [ "access_token", "refresh_token", "expires_in" ], "title": "TokenPair", "type": "object" }, "TransactionOut": { "properties": { "category_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Category Id" }, "comment": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Comment" }, "date": { "format": "date", "title": "Date", "type": "string" }, "deleted": { "title": "Deleted", "type": "boolean" }, "flow_type": { "$ref": "#/components/schemas/FlowType" }, "hold": { "title": "Hold", "type": "boolean" }, "id": { "title": "Id", "type": "integer" }, "income": { "description": "decimal as string", "title": "Income", "type": "string" }, "income_account_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Income Account Id" }, "income_currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Income Currency" }, "income_rub": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Income Rub" }, "is_one_off": { "title": "Is One Off", "type": "boolean" }, "mcc": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Mcc" }, "outcome": { "description": "decimal as string", "title": "Outcome", "type": "string" }, "outcome_account_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Outcome Account Id" }, "outcome_currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Outcome Currency" }, "outcome_rub": { "anyOf": [ { "description": "decimal as string", "type": "string" }, { "type": "null" } ], "title": "Outcome Rub" }, "payee": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Payee" }, "payee_canonical": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Payee Canonical" }, "source_id": { "title": "Source Id", "type": "string" }, "tags": { "items": { "type": "integer" }, "title": "Tags", "type": "array" }, "trip_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Trip Id" }, "ts": { "format": "date-time", "title": "Ts", "type": "string" } }, "required": [ "id", "source_id", "ts", "date", "income", "income_currency", "income_account_id", "income_rub", "outcome", "outcome_currency", "outcome_account_id", "outcome_rub", "payee", "payee_canonical", "comment", "mcc", "hold", "deleted", "flow_type", "category_id", "is_one_off", "trip_id", "tags" ], "title": "TransactionOut", "type": "object" }, "TransactionPage": { "properties": { "items": { "items": { "$ref": "#/components/schemas/TransactionOut" }, "title": "Items", "type": "array" }, "page": { "title": "Page", "type": "integer" }, "page_size": { "title": "Page Size", "type": "integer" }, "total": { "title": "Total", "type": "integer" } }, "required": [ "items", "total", "page", "page_size" ], "title": "TransactionPage", "type": "object" }, "UserOut": { "properties": { "email": { "title": "Email", "type": "string" }, "id": { "title": "Id", "type": "integer" } }, "required": [ "id", "email" ], "title": "UserOut", "type": "object" } }, "securitySchemes": { "HTTPBearer": { "scheme": "bearer", "type": "http" } } }, "info": { "title": "fin-tracker", "version": "0.1.0" }, "openapi": "3.1.0", "paths": { "/api/v1/accounts": { "get": { "description": "Every account, archived ones included — the client decides what to show.", "operationId": "accounts_list", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/AccountOut" }, "title": "Response Accounts List", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "List", "tags": [ "accounts" ] } }, "/api/v1/accounts/{account_id}": { "patch": { "description": "Update the user-owned fields. Everything else is overwritten by the next sync.", "operationId": "accounts_patch", "parameters": [ { "in": "path", "name": "account_id", "required": true, "schema": { "title": "Account Id", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountPatch" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Patch", "tags": [ "accounts" ] } }, "/api/v1/auth/login": { "post": { "operationId": "auth_login", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenPair" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "summary": "Login", "tags": [ "auth" ] } }, "/api/v1/auth/logout": { "post": { "operationId": "auth_logout", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshRequest" } } }, "required": true }, "responses": { "204": { "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "summary": "Logout", "tags": [ "auth" ] } }, "/api/v1/auth/me": { "get": { "operationId": "auth_me", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Me", "tags": [ "auth" ] } }, "/api/v1/auth/refresh": { "post": { "operationId": "auth_refresh", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenPair" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "summary": "Refresh", "tags": [ "auth" ] } }, "/api/v1/cashflow/monthly": { "get": { "description": "The last `months` months, oldest first.", "operationId": "cashflow_monthly", "parameters": [ { "in": "query", "name": "months", "required": false, "schema": { "default": 12, "maximum": 120, "minimum": 1, "title": "Months", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/CashFlowMonth" }, "title": "Response Cashflow Monthly", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Monthly", "tags": [ "cashflow" ] } }, "/api/v1/categories": { "get": { "description": "Flat list of the ZenMoney tag tree; the client nests it by `parent_id`.", "operationId": "categories_list", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/CategoryOut" }, "title": "Response Categories List", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "List", "tags": [ "categories" ] } }, "/api/v1/data-quality": { "get": { "description": "Findings of the latest refresh, most serious first.", "operationId": "metrics_data_quality", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/DataQualityRow" }, "title": "Response Metrics Data Quality", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Data Quality", "tags": [ "metrics" ] } }, "/api/v1/health": { "get": { "operationId": "health_check", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "summary": "Check", "tags": [ "health" ] } }, "/api/v1/metrics/refresh": { "post": { "description": "Rebuild every metric_* table inline (seconds at personal volumes).", "operationId": "metrics_refresh", "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshLogOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Refresh", "tags": [ "metrics" ] } }, "/api/v1/metrics/status": { "get": { "description": "When the metric tables were last rebuilt, and whether it failed.", "operationId": "metrics_status", "responses": { "200": { "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/RefreshLogOut" }, { "type": "null" } ], "title": "Response Metrics Status" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Status", "tags": [ "metrics" ] } }, "/api/v1/networth/breakdown": { "get": { "description": "The latest day's buckets, plus every account's current balance native and in RUB.", "operationId": "networth_breakdown", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NetWorthBreakdown" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Breakdown", "tags": [ "networth" ] } }, "/api/v1/networth/series": { "get": { "description": "Daily net worth; defaults to the last 365 days.", "operationId": "networth_series", "parameters": [ { "in": "query", "name": "from", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "From" } }, { "in": "query", "name": "to", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "To" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/NetWorthDay" }, "title": "Response Networth Series", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Series", "tags": [ "networth" ] } }, "/api/v1/rules": { "get": { "operationId": "rules_list", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/RuleOut" }, "title": "Response Rules List", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "List", "tags": [ "rules" ] }, "post": { "operationId": "rules_create", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RuleCreate" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RuleOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Create", "tags": [ "rules" ] } }, "/api/v1/rules/apply": { "post": { "description": "Re-run the whole metric refresh so edited rules take effect everywhere at once.", "operationId": "rules_apply", "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshLogOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Apply", "tags": [ "rules" ] } }, "/api/v1/rules/stale": { "get": { "description": "Enabled rules that matched nothing in the latest refresh: the payee was renamed,\nor the transaction was re-categorised in ZenMoney.", "operationId": "rules_stale", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/RuleOut" }, "title": "Response Rules Stale", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Stale", "tags": [ "rules" ] } }, "/api/v1/rules/{rule_id}": { "delete": { "operationId": "rules_delete", "parameters": [ { "in": "path", "name": "rule_id", "required": true, "schema": { "title": "Rule Id", "type": "integer" } } ], "responses": { "204": { "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete", "tags": [ "rules" ] }, "patch": { "operationId": "rules_patch", "parameters": [ { "in": "path", "name": "rule_id", "required": true, "schema": { "title": "Rule Id", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RulePatch" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RuleOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Patch", "tags": [ "rules" ] } }, "/api/v1/runway": { "get": { "description": "How many months the liquid reserve covers; null before the first refresh.", "operationId": "cashflow_runway", "responses": { "200": { "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/RunwayOut" }, { "type": "null" } ], "title": "Response Cashflow Runway" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Runway", "tags": [ "cashflow" ] } }, "/api/v1/spending/categories": { "get": { "description": "Expenses of one month by category, largest first.", "operationId": "cashflow_spending", "parameters": [ { "description": "YYYY-MM; defaults to the latest month", "in": "query", "name": "month", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "YYYY-MM; defaults to the latest month", "title": "Month" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/SpendingRow" }, "title": "Response Cashflow Spending", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Spending", "tags": [ "cashflow" ] } }, "/api/v1/sync/runs": { "get": { "operationId": "sync_runs", "parameters": [ { "in": "query", "name": "source", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Source" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 200, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/SyncRunOut" }, "title": "Response Sync Runs", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Runs", "tags": [ "sync" ] } }, "/api/v1/sync/status": { "get": { "operationId": "sync_status", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/SourceStatus" }, "title": "Response Sync Status", "type": "array" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Status", "tags": [ "sync" ] } }, "/api/v1/sync/{source}": { "post": { "operationId": "sync_trigger", "parameters": [ { "in": "path", "name": "source", "required": true, "schema": { "title": "Source", "type": "string" } } ], "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SyncJobOut" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Trigger", "tags": [ "sync" ] } }, "/api/v1/transactions": { "get": { "description": "One page of transactions, newest first, with RUB amounts at each own date's rate.", "operationId": "transactions_list", "parameters": [ { "in": "query", "name": "from", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "From" } }, { "in": "query", "name": "to", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "To" } }, { "in": "query", "name": "account_id", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Account Id" } }, { "in": "query", "name": "category_id", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Category Id" } }, { "in": "query", "name": "flow_type", "required": false, "schema": { "anyOf": [ { "$ref": "#/components/schemas/FlowType" }, { "type": "null" } ], "title": "Flow Type" } }, { "description": "substring of payee or comment", "in": "query", "name": "q", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "substring of payee or comment", "title": "Q" } }, { "in": "query", "name": "include_deleted", "required": false, "schema": { "default": false, "title": "Include Deleted", "type": "boolean" } }, { "in": "query", "name": "page", "required": false, "schema": { "default": 1, "minimum": 1, "title": "Page", "type": "integer" } }, { "in": "query", "name": "page_size", "required": false, "schema": { "default": 50, "maximum": 500, "minimum": 1, "title": "Page Size", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransactionPage" } } }, "description": "Successful Response" }, "default": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }, "description": "Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "List", "tags": [ "transactions" ] } } }, "servers": [ { "url": "/" } ] }