Expenses
GET /expenses
The expenses of the budgets shared with you, filtered as you choose. A list, one page at a time.
Only the expenses of active budgets are listed: those of draft, completed and archived budgets are not.
Keys: personal keys only. Other keys get 403 personal_key_required.
Parameters
Every filter is optional. Filters add up: budget_id and status together keep the expenses of that budget with
that status.
| Parameter | Type | Description |
|---|---|---|
budget_id | string | Only this budget's expenses. |
category_id | string | Only this category's expenses, without its sub-categories'. |
vendor_id | string | Only this vendor's expenses. |
status | string | planned, spent or cancelled. |
from | YYYY-MM-DD | Only the expenses whose period overlaps this day or a later one. |
to | YYYY-MM-DD | Only the expenses whose period overlaps this day or an earlier one. The whole day counts. |
limit | integer | Expenses per page, from 1 to 200. 50 by default. |
cursor | string | The next_cursor of the previous page. |
An expense covers a period, from start_at to end_at. With from and to, an expense is kept if its period
overlaps theirs, even partly, and its amount is returned whole: it is not split by day.
For an expense of a vendor synced from an ads platform (see integration_source in vendors), the period
counts up to today at most.
A budget_id, category_id or vendor_id you can't see gives an empty list, not an error.
Response
A list: data holds the expenses, next_cursor points to the next page.
| Field | Type | Description |
|---|---|---|
id | string | The expense's id. |
budget_id | string | Its budget. |
budget_name | string | |
category_id | string | Its category. |
category_name | string | |
vendor_id | string | Its vendor. |
vendor_name | string | May be null. |
status | string | planned (committed, not spent yet), spent or cancelled. |
type | string | invoice, receipt, manual or other. |
source | string | How it was recorded: manual, import or api. |
amount | amount | The expense's amount, in its own currency. |
currency | string | The expense's currency. |
budget_amount | amount | The same amount in the budget's currency. Budget totals sum this one. |
budget_currency | string | The budget's currency. |
comment | string | May be null or empty. |
start_at | timestamp | When the period the expense covers starts. |
end_at | timestamp | When it ends. |
created_by | object | The member who recorded it: id, first_name, last_name. |
created_at | timestamp | When it was recorded. |
To add expenses up, sum budget_amount: amount may be in different currencies.
Example
The spent expenses of one budget in March 2026:
curl "https://app.spendbaker.com/sb_back/api/v1/expenses?budget_id=7d2f9a40-3c8e-4b16-a5d7-2e9c0f81b4a3&status=spent&from=2026-03-01&to=2026-03-31" \
-H "Authorization: Bearer $SPENDBAKER_KEY"
{
"data": [
{
"id": "e6c0b49d-2f71-4a8e-9d35-0c4b8a7e1f92",
"budget_id": "7d2f9a40-3c8e-4b16-a5d7-2e9c0f81b4a3",
"budget_name": "Marketing 2026",
"category_id": "5e8b1c73-a4f2-4d69-9c0e-7b3a2d1f8e46",
"category_name": "LinkedIn Ads",
"vendor_id": "9a3d6f12-7e4b-4c85-b1a0-6f2e9d7c3b58",
"vendor_name": "Northwind Media",
"status": "spent",
"type": "invoice",
"source": "manual",
"amount": "4200.00",
"currency": "USD",
"budget_amount": "3864.00",
"budget_currency": "EUR",
"comment": "March campaign",
"start_at": "2026-03-01T00:00:00Z",
"end_at": "2026-03-31T00:00:00Z",
"created_by": {
"id": "0b9e4d27-6a13-4f58-b2c9-81e7d4a0f365",
"first_name": "Camille",
"last_name": "Martin"
},
"created_at": "2026-03-02T09:14:31.120842Z"
}
],
"next_cursor": "ZTZjMGI0OWQtMmY3MS00YThlLTlkMzUtMGM0YjhhN2UxZjky"
}
Errors
400 invalid_limit, 400 invalid_cursor, 401, 403, 429 and 500, as in
Errors and limits, and:
| Status | code | When |
|---|---|---|
| 400 | invalid_parameter | An id filter is not an id from this API, status is not one of its values, or from or to is not YYYY-MM-DD. |