MSaving

API routes

Every /v1 route the API serves today.

Base: the server’s own address (locally http://127.0.0.1:8000 with dev.sh, or :8080 for the compose stack). Every route needs Authorization: Bearer <session token> except those marked “no sign-in”. In a browser, only the server’s own origin is allowed (403 origin_not_allowed otherwise). The OpenAPI schema is at /v1/openapi.json.

Conventions: money in integer minor units; ids are UUIDs; editable rows carry version (mismatch → 409); creates take a client-made id and are idempotent; errors are {"detail": "<code>"}. Within /v1 routes and fields are only added.

The server and reference data

Method Path Notes
GET /v1/health {"ok":true}; no sign-in
GET /v1/instance Name, server_version, api_version, signup (invite/open), setup_needed; no sign-in. Clients check it first
GET /v1/currencies ISO 4217 codes and decimals

Getting in (no sign-in)

Method Path Notes
POST /v1/setup The first account, with the setup code from the log; becomes admin. Optional server_name
POST /v1/auth/invite-check {"code"} → {"valid"}, for the join screen
POST /v1/auth/sign-up Username, password, language, timezone, invite_code (unless sign-up is open) → token
POST /v1/auth/sign-in Username, password, code (TOTP or recovery code) when two-factor is on → token
POST /v1/auth/reset A reset link’s token and a new password → token; turns two-factor off

Sign-in security (signed in)

Method Path Notes
POST /v1/auth/sign-out Ends this session
POST /v1/auth/sign-out-others Ends every other session
POST /v1/auth/password Current and new password; ends other sessions
GET /v1/auth/two-factor enabled, recovery_codes_left
POST /v1/auth/two-factor/setup A new secret, its otpauth:// URI and QR code; nothing saved yet
POST /v1/auth/two-factor/enable Secret and a code from it → ten recovery codes
POST /v1/auth/two-factor/recovery-codes A current code → new recovery codes
POST /v1/auth/two-factor/disable A current code

Me (the signed-in user)

Method Path Notes
GET /v1/me Profile, including is_admin
PATCH /v1/me Username, display name, language, timezone (last write wins)
GET /v1/me/status Open, or closed with deletion date
POST /v1/me/delete Close the account (30-day restore)
POST /v1/me/restore Restore a closed account
GET /v1/me/export ZIP of readable CSVs

The server’s admin

Method Path Notes
PATCH /v1/admin/instance Server name, signup mode
GET /v1/admin/users Accounts with last seen, status, two-factor
POST /v1/admin/users/{id}/disable {"disabled": true/false}; disabling ends their sessions
POST /v1/admin/users/{id}/reset A one-time reset token (24 hours)
GET, POST /v1/admin/invites POST: note, days (1 to 30), server (the admin’s origin) → code, link, QR
DELETE /v1/admin/invites/{id} Revoke
GET /v1/admin/update Running and newest version, whether the updater runs, its last status
POST /v1/admin/update Ask the updater to update now (409 updater_off without it)

Books and their contents

Method Path Notes
GET, POST /v1/books POST creates with starter categories unless unticked
GET, PATCH, DELETE /v1/books/{book_id}
GET /v1/books/{book_id}/dashboard Everything the home screen shows, in one call, with rates_source (some sources need a credit)
GET, POST /v1/books/{book_id}/accounts POST takes an opening balance and optional contact_id
PATCH /v1/books/{book_id}/accounts/{id} Includes archive
GET, POST /v1/books/{book_id}/categories
PATCH, DELETE /v1/books/{book_id}/categories/{id} DELETE archives a used category
GET, POST /v1/books/{book_id}/transactions Filters: account_id (with running balance), category_id (with sub-categories), from, to, type, q; pages by after
GET, PUT, DELETE /v1/books/{book_id}/transactions/{id}
GET /v1/books/{book_id}/transactions/{id}/history Every saved version
GET, POST /v1/books/{book_id}/contacts With each person’s balances
PATCH, DELETE /v1/books/{book_id}/contacts/{id} DELETE archives a linked person
GET, POST /v1/books/{book_id}/budgets With current progress
PATCH, DELETE /v1/books/{book_id}/budgets/{id}

Sharing a book

Method Path Notes
GET /v1/books/{book_id}/members Every member: name (username or “Deleted user”), display_name, role, pending, me
POST /v1/books/{book_id}/members Owners: username, role (default editor) → the member list. 409 cannot_invite for an unknown username and for someone already in the book, alike; rate limited
PATCH /v1/books/{book_id}/members/{user_id} Owners: role. 409 owner_required for the last owner
DELETE /v1/books/{book_id}/members/{user_id} Owners remove anyone or cancel an invite; anyone leaves with their own id. 409 owner_required for the last owner
GET /v1/me/book-invites Invites I haven’t answered: book, role, who invited me
POST /v1/me/book-invites/{book_id}/accept Become a member
DELETE /v1/me/book-invites/{book_id} Decline; the invite goes away, nobody is told

Source: msaving/backend/app/api/routes/v1/. This page is the list: a new route comes with a paired docs PR that adds it here.

Edit this page · Report a problem