Developer API
Your budget, scriptable
Rudopo has no bank connections, so your data is exactly what you put in it — and it should be yours to read. A small REST API lets you pull transactions, balances and budget months into a notebook, a spreadsheet, or whatever you already use.
Start here
- 1
Create a token
In Rudopo, open Settings → API tokens and create a token. It is shown once — we store only a hash, so it cannot be recovered afterwards.
- 2
Send it as a bearer token
Every request carries Authorization: Bearer rudopo_pat_YOUR_TOKEN. A token acts as you and reaches only what you can; you can also narrow one to specific budgets.
- 3
Ask for a budget
Every budget-scoped resource takes a budget_id. Start with /budgets to find yours.
Tokens are yours alone. A token reaches only what your account can, can be narrowed to specific budgets, and can be revoked from Settings at any time — revocation takes effect on the next request.
A first request
curl -s "https://rudopo.app/api/v1/transactions?budget_id=YOUR_BUDGET_ID&limit=5" \
-H "Authorization: Bearer rudopo_pat_YOUR_TOKEN"The same thing in Python
No SDK to install — it is an HTTP API, and this is the whole client.
import requests
BASE = "https://rudopo.app/api/v1"
AUTH = {"Authorization": "Bearer rudopo_pat_YOUR_TOKEN"}
budget = requests.get(f"{BASE}/budgets", headers=AUTH).json()["budgets"][0]
r = requests.get(
f"{BASE}/transactions",
params={"budget_id": budget["id"], "limit": 50},
headers=AUTH,
)
r.raise_for_status()
for t in r.json()["transactions"]:
print(t["date"], t["payeeName"], t["amount"])Three things worth knowing first
Money is a string
Amounts are decimal strings in major units with two fraction digits ("-45.00"), never JSON numbers. Parse them with a decimal type — a float will quietly lose cents on someone's ledger.
Dates have no timezone
Transaction dates are YYYY-MM-DD and months are YYYY-MM, exactly as entered. They are calendar dates, not instants; converting them to UTC invents a timezone the data never had.
A bad limit is an error, not a trim
Ask for more rows than the maximum and you get a 400. We would rather fail loudly than hand back fewer rows than you asked for and let you ship a partial sync believing it was complete. The same goes for every other parameter: an unrecognised filter value and a date that does not exist are errors, never a request that quietly did something else.
404 never tells you an id is real
An id that does not exist and an id belonging to someone else answer identically, so a token cannot be used to probe for other people's data. A 403 is only ever about your own token — a missing scope, or a budget outside the list you scoped it to.
Rate limits
| Scope | Limit |
|---|---|
| Per IP, before authentication | 300 / min |
| Per token, reads | 60 / min |
| Per token, writes | 30 / min |
| Per user, all tokens | 120 / min |
| Per user, daily | 20,000 / day |
Every response carries X-RateLimit-* headers, and a refusal carries Retry-After — so a well-behaved client can pace itself instead of discovering the limit by hitting it. The three values describe whichever window above will refuse first, so they always belong together.
Reference
Every endpoint, parameter and response shape is described in an OpenAPI document generated from the code itself, so it cannot drift from what the server actually does.
There is no official client library, on purpose. The API is small enough to call directly, and publishing the description means you can generate a client in whichever language you actually use rather than waiting for us to write one.
Changelog
- 2026-08-27v1 available: read budgets, accounts, transactions, categories, payees, labels and budget months with a personal access token.
New fields and endpoints are added without breaking anything. If an endpoint ever has to change in a way that would break you, it gets at least six months of notice and Deprecation headers first.