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 aYYYY-MM-DDdate, an RFC 3339 timestamp, or unix seconds. - Money —
amountandbalanceare 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.