Money & dates
Amounts are integer cents; months are YYYY-MM; dates are YYYY-MM-DD.
Money is integer cents
Every amount in the API is an integer number of US cents (a 64-bit integer):
| Dollars | In the API |
|---|---|
| $12.34 | 1234 |
| $1,500.00 | 150000 |
| $0.05 | 5 |
Never send floats or strings. Convert at the edges of your program, for example
Math.round(dollars * 100), and format for display by dividing by 100.
- Transaction amounts are always positive. Whether money comes in or goes out is the
transaction's
type:expenseorincome. - Split amounts must add up to the transaction's amount (
splits_do_not_sumotherwise), and each must be positive (split_not_positive). - Computed figures can be negative.
left_to_budgetis negative when you've planned more than your income, and an item'sremainingis negative when it's overspent. Fund balances can go negative too.
Months are YYYY-MM
A budget covers one calendar month and is addressed by YYYY-MM, like 2026-12:
GET /months/2026-12A month either has a budget or doesn't yet. Reading one that doesn't gives 404 with the code
month_not_created. Create it with POST /months/{month}, which copies the most recent earlier
budget (or a default template).
Dates are YYYY-MM-DD
A transaction's date is a plain calendar date with no time or time zone, like 2026-12-03.
Timestamps like created_at are RFC 3339 date-times in UTC.
Budget month vs. date
A transaction also has a budget_month: the month whose budget it counts toward. It's usually
the month of its date, but it doesn't have to be. A rent payment made on November 30th can count
toward December. budget_month is required whenever the transaction has splits, and each split's
item must exist in that month (item_not_in_month otherwise).
IDs are ULIDs
IDs are ULIDs: 26 characters of Crockford base32, like
01J8Z3N4Q5R6S7T8V9W0X1Y2Z3. They sort by creation time. Most are generated by the server; the
exception is transaction IDs, which you generate (see Idempotency).