Skip to Content
DevelopersAPI overview

API overview

Every route is under /v1 and, except the two health checks, needs a signed-in user’s access token (Authorization: Bearer <token>). The full, always-current reference is the Swagger page at /docs on a running API; this page explains the rules that apply everywhere and what exists today.

Rules that apply to every endpoint

RuleWhat it means for you
Money is whole kobo150000 means NGN 1,500. A decimal, zero, negative or over-the-maximum amount is rejected with a 400, never rounded. The maximum is 2,000,000,000 kobo (NGN 20,000,000).
One error shapeEvery failure is { "code", "message", "details" }. details is a list of plain-words problems on a 400. Server faults never reveal internals.
Ids you generateAn entry’s id is a UUID created by the client. Sending the same entry twice never duplicates it. Ids are only unique per person, so one user can never collide with, or probe for, another’s.
Your timezoneToday, this week (Monday to Sunday) and this month are worked out in the person’s own timezone (PATCH /v1/me), not the server’s.
DatesISO 8601 with a time and offset, for example 2026-10-16T09:30:00Z. An entry cannot be dated more than a day in the future.
PagingLists use a cursor: pass the nextCursor you were given as ?cursor=. Paging is stable even when many entries share a timestamp.
Soft deleteDeleting an entry hides it everywhere but keeps the row, so offline devices can learn about the deletion. Repeating a delete is safe.
Unknown fields are rejectedSending a field the endpoint does not know (for example userId or role) is a 400. This is deliberate.
You only ever see your own dataA request for someone else’s record behaves exactly like a request for one that does not exist.

What exists today

AreaEndpoints
HealthGET /health, GET /health/ready (no sign-in needed)
MeGET /me, PATCH /me (name, language, income pattern, timezone only)
EntriesGET /entries (filters, search, paging), POST /entries, GET/PATCH/DELETE /entries/{id}, POST /entries/sync
AccountsGET/POST /accounts, PATCH/DELETE /accounts/{id} (labels you keep; never bank links)
CategoriesGET/POST /categories, PATCH/DELETE /categories/{id} (23 built-in Nigerian categories plus your own)
CapturePOST /capture/text, GET /capture/{id}, POST /capture/{id}/confirm
BudgetsGET/POST /budgets, PATCH/DELETE /budgets/{id}, GET /budgets/safe-to-spend
InsightsGET /insights/summary, GET /insights/weekly
HabitsGET /habits
NotificationsGET /notifications/preferences, PATCH /notifications/preferences/{type}, POST/DELETE /push/subscribe
PrivacyGET /me/consents, PUT /me/consents/{purpose}, GET /me/export, DELETE /me

What does not exist yet

These need an outside account, a provider decision or real data first, and are Planned:

FeatureWaiting for
Voice logging (/capture/voice)A speech-to-text provider, and a set of real voice notes to measure accuracy
WhatsApp logging and linkingA WhatsApp Business number and Meta account
Forwarded bank-alert parsing (/capture/alert)Real alert samples from each bank, so the parsers are not invented
Receipt photos (/capture/receipt)Phase 2
The AI assistant (/assistant/messages)An AI provider and the PII-stripping gateway
Sending push and email remindersA job queue (Redis, or an alternative) and an email provider. The rules for when to send, and the at-most-once guarantee, are built and tested
Groups (ajo), organisations, billingPhase 2

Calling it from the web app

The web app never calls the API from the browser with a token. It signs in on the server, keeps the session in a secure cookie, and its own server forwards calls to the API. See ADR 0005.

Last updated on