Pathayam

API reference

Every screen is already an endpoint

The app is server-rendered, so there is no second API to keep in sync. A personal token authenticates a script against the same routes your browser uses.

How it works

Authentication

The host in every example below is your own instance — the machine you self-host on, or your hosted subdomain. The public demo at demo.pathayam.app signs everyone in automatically and issues no tokens, so these examples will not run against it.

One header on every request: Authorization: Bearer bgt_…. Tokens are minted in Settings, scoped read or read-write, and shown exactly once.

Idempotency

Every write accepts Idempotency-Key. Replaying a key returns the original result instead of acting twice, so a timeout you never saw is safe to retry.

Responses

Reads return HTML — this is the same app your browser talks to. /export.json, the CSVs and /healthz return data. Writes redirect on success.

Amounts are whole rupees in requests and integer paise internally, so nothing is ever stored as a float. Dates are YYYY-MM-DD and months are YYYY-MM, both in IST.

Budget & money

Everything that moves money between envelopes. These are the routes that change what your budget says.

GET / The month grid

The budget screen for a month: groups, categories, assigned, activity and available, with Ready to Assign and the digest.

Scope

read or higher

Parameters

NameTypeDescription
monthstringoptionalYYYY-MM. Defaults to the current month in IST.

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS https://pathayam.yourdomain.com/?month=2026-09 \
  -H "Authorization: Bearer bgt_…"
POST /assign Assign to a category

Set the amount assigned to one category in one month. This is an absolute value, not a delta — sending 4500 makes the assignment 4500, whatever it was before.

Scope

read-write

Parameters

NameTypeDescription
monthstringrequiredYYYY-MM.
category_idstringrequiredThe category receiving the money.
amountintegerrequiredRupees. Accepts an expression such as 450+120.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/assign \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "month=2026-09&category_id=cat_7f3&amount=4500"
POST /move Move between envelopes

Move money from one category to another within the same month. Ready to Assign is unaffected — the total assigned does not change, only where it sits. This is how you cover an overspend.

Scope

read-write

Parameters

NameTypeDescription
monthstringrequiredYYYY-MM.
from_category_idstringrequiredWhere the money comes from.
to_category_idstringrequiredWhere it goes.
amountintegerrequiredRupees.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/move \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "month=2026-09&from_category_id=cat_hol&to_category_id=cat_eat&amount=1320"
POST /hold Hold income for next month

Take an amount out of this month's Ready to Assign and place it at the top of next month's. Send 0 to release everything currently held.

Scope

read-write

Parameters

NameTypeDescription
monthstringrequiredThe month holding the money back.
amountintegeroptionalRupees. Empty or 0 releases the hold.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/hold \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "month=2026-09&amount=139900"
GETPOST /auto-assign Fund every target

GET previews what funding all targets would do. POST commits it. Money is spent down the budget in your own order, so a short month funds the top of the list first.

Scope

read-write

Parameters

NameTypeDescription
monthstringrequiredYYYY-MM.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS https://pathayam.yourdomain.com/auto-assign?month=2026-09 \
  -H "Authorization: Bearer bgt_…"
GET /explain/ready-to-assign Why that number

The events that produced Ready to Assign for a month, in order — income, assignments, holds, and anything carried in.

Scope

read or higher

Parameters

NameTypeDescription
monthstringoptionalYYYY-MM.

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS https://pathayam.yourdomain.com/explain/ready-to-assign?month=2026-09 \
  -H "Authorization: Bearer bgt_…"

Accounts & transactions

Where money actually arrives and leaves.

GET /accounts List accounts

Every account with its cleared, uncleared and working balances, grouped into budget, credit and tracking.

Scope

read or higher

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS https://pathayam.yourdomain.com/accounts \
  -H "Authorization: Bearer bgt_…"
POST /add Record a transaction

Create one transaction. Money out must name a category — the requirement is enforced on the server, not only in the form. Money in is exempt, because its job is to land in Ready to Assign.

Scope

read-write

Parameters

NameTypeDescription
account_idstringrequiredThe account it happened on.
directionstringrequiredin or out.
amountintegerrequiredRupees, always positive. Direction carries the sign.
datestringrequiredYYYY-MM-DD.
category_idstringoptionalRequired when direction is out.
payeestringoptionalFree text. Matched against known payees.
memostringoptionalA note to your future self.
tagsstringoptionalComma-separated.
clearedbooleanoptionalWhether the bank has confirmed it.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/add \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "account_id=acc_hdfc&direction=out&amount=1240" \
  -d "date=2026-09-12&category_id=cat_gro&payee=Zepto"
POST /transfer Move between your accounts

A transfer is not spending and is never counted as such. Paying a credit card is a transfer from a budget account to that card.

Scope

read-write

Parameters

NameTypeDescription
from_account_idstringrequiredSource account.
to_account_idstringrequiredDestination account.
amountintegerrequiredRupees.
datestringoptionalYYYY-MM-DD. Defaults to today.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/transfer \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "from_account_id=acc_hdfc&to_account_id=acc_card&amount=11600"
GET /cards Cards by due date

Every credit account ordered by what falls due next, with what is owed, what the payment envelope holds, and anything unfunded.

Scope

read or higher

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS https://pathayam.yourdomain.com/cards \
  -H "Authorization: Bearer bgt_…"
POST /transaction/:id/categorise File one transaction

Assign a category to an existing transaction. This is also the learning signal: filing the same payee twice proposes a rule.

Scope

read-write

Parameters

NameTypeDescription
idpathrequiredTransaction id.
category_idstringrequiredThe envelope it belongs to.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/transaction/txn_9a2/categorise \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "category_id=cat_gro"
POST /transaction/:id/delete Delete a transaction

Soft delete, recorded in the event log and reversible for thirty days from Activity.

Scope

read-write

Parameters

NameTypeDescription
idpathrequiredTransaction id.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/transaction/txn_9a2/delete \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)"

Import & review

Nothing posts itself. Everything arrives here first.

GET /review The review queue

Everything awaiting a decision: uncategorised spending, suspected duplicates, overspent categories, unfunded cards, proposed rules and money you are owed.

Scope

read or higher

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS https://pathayam.yourdomain.com/review \
  -H "Authorization: Bearer bgt_…"
POST /import Import a CSV

Paste statement rows as CSV. Headers are detected and a per-bank column mapping can be saved for next time. Rows land staged, never posted.

Scope

read-write

Parameters

NameTypeDescription
account_idstringrequiredWhich account these rows belong to.
csvstringrequiredThe raw CSV text.
profile_idstringoptionalA saved column mapping to apply.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/import \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-urlencode "csv@statement.csv" -d "account_id=acc_hdfc"
POST /import/pdf Upload a statement PDF

Multipart upload of a bank statement. The bank is recognised from its own layout, the file is decrypted in-process if it is password-protected, and the parse is checked against the statement's closing balance.

Scope

read-write

Parameters

NameTypeDescription
filefilerequiredThe PDF, as multipart form data.
account_idstringrequiredWhich account it belongs to.
passwordstringoptionalOmit it to let the app derive it from your saved identity.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/import/pdf \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@statement.pdf" -F "account_id=acc_hdfc"
POST /import/undo Undo an import batch

Reverses an entire import and every row it created, in one step.

Scope

read-write

Parameters

NameTypeDescription
batch_idstringrequiredFrom the import log.

Responses

  • 303 — Success. Follow Location to the updated screen.
  • 400 — A field was missing or could not be parsed; the message says which.
  • 401 — No token, or a token without write scope.
  • 409 — Replayed idempotency key with a different body.

Example

curl -sS -X POST https://pathayam.yourdomain.com/import/undo \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)" -d "batch_id=imp_41c"

Query, activity & export

Reading everything back out, including all of it at once.

GET /query Filter transactions

The filterable, groupable table. Totals are summed over every row that matched, not the page rendered — the response says how many matched.

Scope

read or higher

Parameters

NameTypeDescription
fromstringoptionalYYYY-MM-DD.
tostringoptionalYYYY-MM-DD.
category_idstringoptionalRestrict to one envelope.
account_idstringoptionalRestrict to one account.
payeestringoptionalSubstring match on cleaned and raw text.
group_bystringoptionalcategory, payee, month or account.

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS "https://pathayam.yourdomain.com/query?from=2025-10-01&to=2026-09-30&group_by=category" \
  -H "Authorization: Bearer bgt_…"
GET /query.csv Query results as CSV

The same filter, as CSV, uncapped. The figures match what the screen showed.

Scope

read or higher

Parameters

NameTypeDescription
optionalAccepts every parameter /query does.

Responses

  • 200text/csv.
  • 401 — No token.

Example

curl -sS "https://pathayam.yourdomain.com/query.csv?from=2026-04-01" \
  -H "Authorization: Bearer bgt_…" -o spend.csv
GET /activity Every change made

The append-only event log, newest first, with the undo for each entry. An undo is itself an entry — nothing is edited away.

Scope

read or higher

Parameters

NameTypeDescription
limitintegeroptionalEntries per page.

Responses

  • 200 — The rendered screen, as HTML.
  • 401 — No token, or a token that has been revoked.
  • 429 — Rate limit exceeded. Retry after the interval in the response.

Example

curl -sS https://pathayam.yourdomain.com/activity \
  -H "Authorization: Bearer bgt_…"
POST /activity/:id/undo Undo one event

Reverses a single recorded change within thirty days. Refuses when the record is load-bearing for a loan instalment, a portfolio lot or a reconciliation, and says which.

Scope

read-write

Parameters

NameTypeDescription
idpathrequiredEvent id from Activity.

Responses

  • 303 — Undone.
  • 409 — Refused — the response explains what depends on it.
  • 410 — Older than the thirty-day window.

Example

curl -sS -X POST https://pathayam.yourdomain.com/activity/evt_88c/undo \
  -H "Authorization: Bearer bgt_…" \
  -H "Idempotency-Key: $(uuidgen)"
GET /export.json Export everything

The complete dataset in an open format: accounts, transactions, assignments, lots, loans and events. Not a summary and not a subset. The statement identity and any Gmail refresh token are excluded, and a test asserts their absence.

Scope

read or higher

Responses

  • 200application/json, sent as a download.

Example

curl -sS https://pathayam.yourdomain.com/export.json \
  -H "Authorization: Bearer bgt_…" -o pathayam-backup.json
GET /healthz Health probe

For your uptime monitor. Returns the application state without revealing anything about the data.

Scope

public — no token needed

Responses

  • 200application/json{"ok":true}.
  • 503 — Started but not healthy.

Example

curl -sS https://pathayam.yourdomain.com/healthz

What a token cannot reach

A deny-list of path prefixes rather than a note in a review checklist. A token that could mint tokens turns one leak into permanent access, and a token that could change the allow-list turns it into somebody else's household.

PrefixWhy it is blocked
/membersThe household allow-list. A token must not change who is allowed in.
/tokensA token must not mint or revoke tokens, including itself.
/impersonateImpersonation is a session-only, logged, human action.
/authSign-in, SSO, and the development bypass state.
/signoutThere is nothing for a token to sign out of.

Leaving should be as easy as arriving

One endpoint returns everything in an open format, and the database is a SQLite file you can open with anything. Nothing about the format needs this app to read it.

Read the guides