Skip to content

REST API

The REST API is the primary programmatic surface. All responses are JSON; timestamps are RFC 3339 (UTC); money fields are exact decimal strings exactly as the source returns them. Every route is gated by an auth tier — read, write, or admin — and all tiers are open when no token is configured.

Base path: /api/v1. Source: internal/api.

Conventions

  • Auth — send Authorization: Bearer <token-or-key> (see Authentication).
  • Pagination — list endpoints accept ?limit= (default 100, max 1000) and ?offset=.
  • Time filters — ?since= / ?until= accept a YYYY-MM-DD date, an RFC 3339 timestamp, or unix seconds.
  • Money — amount and balance are strings; never parse them as floats if you need exactness.

Operational

Method & path Tier Description
GET /healthz open Liveness probe (200 ok).
GET /readyz open Readiness probe (pings the database).
GET /metrics open Prometheus metrics.
GET /api/v1/auth open {auth_required, authenticated} — lets a client know whether to prompt.

Read tier

Method & path Description
GET /api/v1/organizations List organizations.
GET /api/v1/accounts List accounts (?org_id= to filter).
GET /api/v1/accounts/{id} Get one account.
GET /api/v1/accounts/{id}/transactions Transactions for an account.
GET /api/v1/transactions List transactions (?label_key= + optional ?label_value= to drill down).
GET /api/v1/transactions/search Search (?q=); returns {query, total, transactions}.
GET /api/v1/transactions/{id} Get one transaction.
GET /api/v1/transactions/{id}/history The transaction's version history.
GET /api/v1/transactions/{id}/provenance The transaction's provenance: source, identity, and transformation lineage.
GET /api/v1/transactions/{id}/relationships The transaction's relationships (outbound + derived inbound edges).
GET /api/v1/labels Labels with per-pair transaction counts.
GET /api/v1/extensions Extension vocabulary with per-key counts.
GET /api/v1/relationships Relationship kind vocabulary with per-kind edge counts.
GET /api/v1/rules · GET /api/v1/rules/{id} List / get rules.
GET /api/v1/plugins · GET /api/v1/plugins/{id} List / get plugins (when enabled).
GET /api/v1/plugins/pages · GET /api/v1/plugins/pages/{name} List plugin dashboard pages / render one (runs the plugin's OnPageRender hook).
GET /api/v1/events Read the event stream from a cursor (?after=, ?type=, ?entity_type=, ?entity_id=, ?limit=, ?newest). Returns {events, next}.
GET /api/v1/events/{sequence} Get one event by sequence.
GET /api/v1/events/stream Live SSE tail (?after= to replay then follow).
GET /api/v1/sync · GET /api/v1/sync/history Latest sync status / recent runs (?limit=).
GET /api/v1/sources Every ingestion source — active and inactive — with readiness, credential shape, and its editable config; returns {enabled, restart_required, sources}.
GET /api/v1/config Effective bootstrap configuration, secrets redacted (powers Settings).
GET /api/v1/settings Every editable setting with its value, override state, and whether a restart is pending. Secrets are never echoed.
GET /api/v1/update Self-update status (when update.check is on).

Write tier

Method & path Description
POST /api/v1/accounts Create a manual account ({"name","currency","balance"}); source is manual.
PUT /api/v1/accounts/{id} Edit a manual account (409 for a synced account).
DELETE /api/v1/accounts/{id} Delete a manual account and its transactions (409 for a synced account).
POST /api/v1/transactions Create a manual transaction ({"account_id","amount","date",...}); 400 on a bad amount/date or unknown account.
PUT /api/v1/transactions/{id} Edit a manual transaction's core fields (409 for a synced transaction).
DELETE /api/v1/transactions/{id} Delete a manual transaction (409 for a synced transaction).
PUT /api/v1/transactions/{id}/labels Replace a transaction's labels ({"labels":{"category":"food"}}).
DELETE /api/v1/labels/{key} Remove a label key from every transaction (?value= to scope).
PUT /api/v1/transactions/{id}/extensions Replace a transaction's extensions.
POST /api/v1/transactions/{id}/relationships Add an outbound relationship edge ({"kind":"refund_of","target":"<id>"}).
DELETE /api/v1/transactions/{id}/relationships Remove an edge (?kind=&target=).
POST /api/v1/rules Create a rule; validates the query, 400 on error.
PUT /api/v1/rules/{id} · DELETE /api/v1/rules/{id} Replace / delete a rule.
POST /api/v1/rules/{id}/run Apply one rule to existing transactions; returns {matched, updated}.
POST /api/v1/rules/run Apply all enabled rules to existing transactions.
POST /api/v1/sync Trigger a sync (async, returns 202).
POST /api/v1/sources/{type}/sync Trigger a sync of one source (async, returns 202).
POST /api/v1/plugins/pages/{name}/action Press a button on a plugin's dashboard page ({"id":"<action>","params":{…}}; runs OnPageAction).

Admin tier (dashboard token only)

Method & path Description
PUT /api/v1/sources/{type}/credential Set (or, for a multi-credential source, add) a source credential — applies live, no restart.
DELETE /api/v1/sources/{type}/credentials/{id} Remove one credential of a multi-credential source (e.g. disconnect one bank).
GET /api/v1/sources/{type}/oauth/start Begin a source's browser OAuth flow (returns the consent URL).
PUT /api/v1/simplefin/credential Back-compat alias for the SimpleFIN credential.
PUT /api/v1/settings/{key} Permanently set one setting ({"value": …}); validated before storing, 404 unknown key, 400 bad value.
DELETE /api/v1/settings/{key} Reset a setting: remove its stored override so the config file/env value applies after the next restart.
POST /api/v1/system/restart Restart kasas in place (re-exec) so pending setting changes take effect.
POST /api/v1/security/token · DELETE … Generate/set or revoke the dashboard token.
POST /api/v1/security/api-keys · GET … · DELETE …/{id} Mint / list / revoke API keys.
GET/POST/PUT/DELETE /api/v1/webhooks (+ /{id}/test, /{id}/rotate-secret) Manage webhooks.
POST /api/v1/plugins/{id}/enable · /disable · /reload · DELETE /api/v1/plugins/{id} Plugin lifecycle (DELETE uninstalls, running the cleanup hook).
GET /api/v1/plugins/registry · POST /api/v1/plugins/registry/{name}/install Browse / install from the community marketplace.
POST /api/v1/update Install the latest release in place (when update.allow_apply is on).

Examples

# recent transactions for an account, filtered by label
curl "localhost:8080/api/v1/transactions?since=2024-01-01&limit=50"
curl "localhost:8080/api/v1/transactions?label_key=category&label_value=food"

# search: coffee outflows in 2024
curl "localhost:8080/api/v1/transactions/search?q=coffee%20amount:%3C0%20date:2024"

# poll the event stream forward from a cursor
curl "localhost:8080/api/v1/events?after=42&limit=100"   # -> {"events":[…],"next":57}

# manually enter a transaction into an account
curl -X POST localhost:8080/api/v1/transactions \
  -H 'Content-Type: application/json' \
  -d '{"account_id":"<id>","amount":"-12.34","date":"2024-03-15","description":"Coffee"}'

DTOs

Handlers convert internal db models to stable JSON DTOs in dto.go: labels decode to a {key:value} object and extensions to a structured JSON object; event data and history snapshots are free-form JSON. These same DTOs back the MCP tools, so REST and MCP return identical shapes.