# API reference

> Versioned /api/v1/ routes with a unified error shape. Full machine-readable
> schema: /openapi.json (OpenAPI 3.1).

## config

- `GET /api/v1/config` — Get runtime app configuration (storage, demo mode, user_id, features)
- `PUT /api/v1/config` — Update runtime app configuration
- `POST /api/v1/config/test-openai` — Validate an OpenAI API key and persist it to data/.env on success
- `POST /api/v1/config/test-s3-backup` — Verify an S3 bucket is a usable attachment-backup target

## ingestion

- `POST /api/v1/transactions` — Add a transaction manually (bypasses email pipeline)
- `POST /api/v1/transactions/upload-eml` — Upload a raw .eml file and parse via the email pipeline

## transactions

- `GET /api/v1/transactions` — List active (non-deleted) transactions for a month
- `GET /api/v1/transactions/all` — Combined active + attention + trash buckets for a month
- `GET /api/v1/transactions/attention` — Transactions needing review (uncategorized, not ignored, not deleted)
- `GET /api/v1/transactions/bulk` — Combined transactions across multiple months (max 12)
- `PATCH /api/v1/transactions/bulk` — Update categories on many transactions in a single request
- `GET /api/v1/transactions/latest` — Freshness probe — max DateFileName, optionally scoped to a month
- `GET /api/v1/transactions/trash` — Soft-deleted transactions for a month
- `DELETE /api/v1/transactions/{tx_id}` — Hard-delete a transaction (irreversible)
- `PATCH /api/v1/transactions/{tx_id}` — Partial update — category, state (active/ignored/trashed), and/or reviewed
- `PUT /api/v1/transactions/{tx_id}/comment` — Set or update the user comment on a transaction
- `POST /api/v1/transactions/{tx_id}/delete` — Toggle the soft-delete flag (move to trash / restore)
- `GET /api/v1/transactions/{tx_id}/detail` — Full transaction record including email body and headers
- `PUT /api/v1/transactions/{tx_id}/fields` — Update editable transaction fields (company, amount, transaction_type)
- `POST /api/v1/transactions/{tx_id}/ignore` — Toggle the ignored flag on a transaction
- `POST /api/v1/transactions/{tx_id}/review` — Mark a transaction's category as manually reviewed

## categories

- `GET /api/v1/categories` — List predefined categories

## summary

- `GET /api/v1/summary` — Monthly spending summary with previous-month comparison
- `GET /api/v1/summary/trend` — Multi-month spending trend (2-12 months)

## budget

- `GET /api/v1/budget/config` — Get budget targets and groups for a year
- `PUT /api/v1/budget/config` — Replace budget targets and groups for a year
- `GET /api/v1/budget/historical-averages` — Per-category historical monthly averages over the last N months
- `GET /api/v1/budget/status` — YTD budget pace status with per-category and per-group breakdown

## insights

- `GET /api/v1/insights/context` — Raw context dict the AI briefing uses (for inspection / external automation)
- `POST /api/v1/insights/generate` — Kick off background AI generation of a monthly spending briefing
- `GET /api/v1/insights/saved` — List saved insight briefings for a month
- `GET /api/v1/insights/saved/{insight_id}` — Get the markdown content of a saved insight briefing
- `GET /api/v1/insights/status` — Background generation status (idle/running/error)

## overrides

- `GET /api/v1/overrides` — List all category override rules
- `POST /api/v1/overrides/consolidate` — Atomically replace member overrides with a single canonical override
- `GET /api/v1/overrides/duplicates` — List override groups sharing a normalized merchant key
- `GET /api/v1/overrides/match` — Preview the tiered category resolver against current overrides + aliases
- `GET /api/v1/overrides/suggestions` — Suggest new override rules from manual category corrections
- `POST /api/v1/overrides/suggestions/dismissed` — Dismiss an override suggestion (it stops surfacing until a newer correction)
- `DELETE /api/v1/overrides/suggestions/dismissed/{key}` — Reverse a previous dismissal (suggestion may resurface)
- `PUT /api/v1/overrides/{company}` — Pin a company → category override
- `DELETE /api/v1/overrides/{company}` — Remove a company → category override

## ignore-rules

- `GET /api/v1/ignore-rules` — List all merchant auto-ignore rules
- `POST /api/v1/ignore-rules` — Add a merchant auto-ignore rule
- `POST /api/v1/ignore-rules/apply` — Backfill Ignored on existing transactions matching a rule (or all rules)
- `GET /api/v1/ignore-rules/suggestions` — Suggest ignore rules from merchants you habitually ignore by hand
- `GET /api/v1/ignore-rules/suggestions/dismissed` — List dismissed ignore-rule suggestions, newest first
- `POST /api/v1/ignore-rules/suggestions/dismissed` — Dismiss a suggested merchant so it stops being surfaced
- `DELETE /api/v1/ignore-rules/suggestions/dismissed/{merchant}` — Reverse a suggestion dismissal so the merchant may resurface
- `DELETE /api/v1/ignore-rules/{pattern}` — Remove a merchant auto-ignore rule

## category-management

- `POST /api/v1/categories` — Add a category, optionally placing it in a budget group
- `GET /api/v1/categories/icons` — Map of user-set category icon overrides
- `PUT /api/v1/categories/icons` — Set or update a category's icon override
- `DELETE /api/v1/categories/icons` — Remove a category's icon override (revert to default)
- `GET /api/v1/categories/managed` — List categories with their group memberships and version
- `DELETE /api/v1/categories/{name}` — Delete a category, optionally reassigning its transactions
- `PUT /api/v1/categories/{name}/group` — Move a category to a different budget group, or remove from all groups
- `GET /api/v1/categories/{name}/usage` — Counts of transactions, overrides, and budget membership for a category
- `PUT /api/v1/categories/{old_name}` — Rename a category and cascade across overrides, budget, transactions

## groups

- `GET /api/v1/groups` — Get budget category groups for a year
- `PUT /api/v1/groups` — Replace budget category groups for a year

## search

- `GET /api/v1/transactions/export` — Stream filtered transactions as CSV
- `GET /api/v1/transactions/search` — Cross-month transaction search with filters
- `POST /api/v1/transactions/search-by-filter` — Cross-month transaction search with array-shaped filters (POST body)

## statements

- `POST /api/v1/statements/import` — Execute import/enrich/update actions for statement transactions
- `POST /api/v1/statements/upload` — Upload a PDF statement, parse, and reconcile against transactions
- `POST /api/v1/statements/{statement_id}/reparse` — Re-parse a statement PDF, preserving prior user edits

## statements-crud

- `GET /api/v1/statements` — List all uploaded statements
- `GET /api/v1/statements/{statement_id}` — Get a statement with all its parsed transactions
- `DELETE /api/v1/statements/{statement_id}` — Delete a statement and its parsed transactions
- `GET /api/v1/statements/{statement_id}/download` — Download the original PDF for a statement
- `PATCH /api/v1/statements/{statement_id}/transactions` — Bulk-update statement transaction actions
- `PATCH /api/v1/statements/{statement_id}/transactions/{row_id}` — Update a single statement transaction's action (auto-save), keyed by row_id

## attachments

- `GET /api/v1/attachments` — List attachments, optionally filtered by link status and kind
- `POST /api/v1/attachments` — Upload a receipt or document, optionally linked to a transaction
- `DELETE /api/v1/attachments/{attachment_id}` — Delete an attachment and its file from disk
- `GET /api/v1/attachments/{attachment_id}/candidates` — Rank the transactions a parsed receipt might explain
- `GET /api/v1/attachments/{attachment_id}/file` — Download the attachment file, served inline with our stored content-type
- `POST /api/v1/attachments/{attachment_id}/link` — Link an attachment to a transaction, or unlink it
- `POST /api/v1/attachments/{attachment_id}/parse` — Parse a receipt attachment with the configured AI provider
- `GET /api/v1/transactions/{tx_id}/attachments` — List attachments linked to a transaction

## income-statement

- `GET /api/v1/income-statement` — Annual income vs. expenses view with projection and savings rate

## tax

- `GET /api/v1/tax-pack` — Calendar-year tax pack: claim-line totals with per-transaction evidence
- `GET /api/v1/tax-pack/export` — Download the year's tax pack as a zip of CSVs plus evidence files
- `POST /api/v1/tax-pack/items` — Force a transaction into a claim line, or exclude it from one
- `DELETE /api/v1/tax-pack/items/{tx_id}` — Clear a per-transaction tax override
- `GET /api/v1/tax-pack/lines` — Selectable claim lines for the include-override picker

## merchants

- `GET /api/v1/merchants/intelligence` — Recurring-charge detection, price-change alerts, committed burn rate

## journal

- `GET /api/v1/journal` — Day-grouped transaction timeline for a month

## daily-summaries

- `GET /api/v1/journal/summaries` — List saved AI day summaries for a month
- `POST /api/v1/journal/summaries/generate` — Kick off background AI generation of day summaries for a month
- `GET /api/v1/journal/summaries/status` — Background generation status (idle/running/error)

## merchant-aliases

- `GET /api/v1/merchant-aliases` — List all merchant aliases (raw → canonical mappings)
- `PUT /api/v1/merchant-aliases/{raw_name}` — Create or update a merchant alias (raw → canonical)
- `DELETE /api/v1/merchant-aliases/{raw_name}` — Delete a merchant alias by raw name

## data

- `POST /api/v1/data/export` — Stream a full-data backup zip (transactions + config)
- `POST /api/v1/data/import/commit` — Apply a previously-previewed import using the chosen strategy
- `POST /api/v1/data/import/preview` — Stage a backup upload and return a dry-run dedup summary
- `GET /api/v1/data/s3-backup-status` — Read the S3 attachment-backup config and last-run state

## parse-failures

- `GET /api/v1/parse-failures` — List quarantined parse failures (summaries only, no email body)
- `POST /api/v1/parse-failures/retry-all` — Re-run the deterministic parsers across a whole institution's quarantined backlog
- `GET /api/v1/parse-failures/{failure_id}` — Get a single quarantined parse failure, including the email body
- `DELETE /api/v1/parse-failures/{failure_id}` — Dismiss a quarantined parse failure
- `POST /api/v1/parse-failures/{failure_id}/resolve` — Record a hand-entered transaction for a quarantined email and mark it resolved
- `POST /api/v1/parse-failures/{failure_id}/retry` — Re-run the deterministic parsers against a quarantined email
- `POST /api/v1/parse-failures/{failure_id}/to-fixture` — Write a scrubbed test-fixture pair from a quarantined email (dev checkout only)

## auth

- `POST /api/v1/auth/chatgpt/disconnect` — Disconnect a previously-linked ChatGPT account
- `POST /api/v1/auth/chatgpt/start` — Begin the ChatGPT device-code sign-in via the Codex CLI
- `GET /api/v1/auth/chatgpt/status` — Poll the ChatGPT sign-in state

## webapp-auth

- `POST /api/v1/auth/login` — Issue a webapp session cookie
- `POST /api/v1/auth/logout` — Clear the caller's webapp session cookie
- `POST /api/v1/auth/set-password` — Set or change the webapp password (TOFU on first set)
- `POST /api/v1/auth/sign-out-all` — Bump session_version, invalidating all existing cookies

## health

- `GET /api/v1/health` — Liveness probe with last-activity snapshot

## coverage

- `GET /api/v1/coverage` — Per-institution bank-alert cadence and passive email-capture rate

## activity

- `GET /api/v1/activity` — List agent activity ledger entries, newest first
- `POST /api/v1/activity/{entry_id}/revert` — Revert a single ledger entry, restoring the resource's prior state
- `GET /api/v1/whoami` — Resolve the current caller's identity (token, session, TOFU, or dev-bypass)
