Wallet & Board API
contactId/orderId are Board-only).
Getting Started
Wallet
Base URL:
https://rest.budgetbakers.com/wallet
OpenAPI Spec:
Get API Token:
Board
Base URL:
https://rest.budgetbakers.com/board
OpenAPI Spec:
Get API Token:
Authentication
All endpoints require an API token (Premium plan required). Add it to the Authorization header:
Authorization: Bearer <your_api_token>
Pagination
All User Data endpoints support pagination:
| Parameter | Default | Max | Description |
|---|---|---|---|
limit | 30 | 200 | Items per page |
offset | 0 | - | Items to skip |
Response includes nextOffset when more results are available.
Rate Limiting
The API uses Token Bucket rate limiting: a sustained hourly budget plus a small burst allowance, so short bursts pass while the average rate is enforced.
- Sustained capacity (production): 300 requests/hour per client
- Burst: short bursts above the average are absorbed by a separate burst bucket; write operations consume more burst tokens than reads
- One budget per client: REST and MCP requests share the same bucket
- Exceeding the limit returns
429 Too Many Requestswith aRetry-Afterheader
| Header | Example | Description |
|---|---|---|
X-RateLimit-Limit | 300 | Maximum sustained request capacity |
X-RateLimit-Remaining | 287 | Remaining capacity |
Query Filter Prefixes
Some parameters require filter prefixes: prefix.value
amount=gte.100 → amount ≥ 100
Text Filters
| Prefix | Meaning | Example |
|---|---|---|
eq. | Exact match | payee=eq.Amazon |
contains. | Contains (case-sensitive) | note=contains.Bill |
contains-i. | Contains (case-insensitive) | note=contains-i.grocery |
Text filters can be specified up to 2 times for AND logic, e.g.
note=contains-i.grocery¬e=contains-i.market.
Range Filters
For numeric and datetime fields:
| Prefix | Meaning | Numeric | Datetime |
|---|---|---|---|
eq. | Equals | amount=eq.100 | createdAt=eq.2024-01-15T10:30:00Z |
gt. | Greater than | amount=gt.100 | createdAt=gt.2024-01-01T00:00:00Z |
gte. | ≥ | amount=gte.100 | createdAt=gte.2024-01-01T00:00:00Z |
lt. | Less than | amount=lt.500 | createdAt=lt.2024-12-31T23:59:59Z |
lte. | ≤ | amount=lte.500 | createdAt=lte.2024-12-31T23:59:59Z |
Date-only values
When date-only (no time) is provided, whole-day UTC semantics apply:
| Filter | Equivalent | Meaning |
|---|---|---|
gt.2025-01-14 | gte.2025-01-15T00:00:00Z | From Jan 15 |
gte.2025-01-14 | gte.2025-01-14T00:00:00Z | From Jan 14 |
lt.2025-01-15 | lt.2025-01-15T00:00:00Z | Before Jan 15 |
lte.2025-01-15 | lt.2025-01-16T00:00:00Z | Through Jan 15 |
eq.2025-01-13 | gte...<lt... | Entire Jan 13 |
Range filters support up to 2 conditions (AND logic):
amount=gte.100&amount=lte.500recordDate=gte.2024-01-01&recordDate=lt.2024-02-01
Data Synchronization
User data is synchronized from the app. Changes may not appear immediately via API.
Initial Sync
Sync begins when you generate your first API key. Until complete, requests return 409 Conflict:
{
"error": "init_sync_in_progress",
"message": "Data synchronization in progress. Please retry later.",
"retry_after_minutes": 5
}
Ongoing Sync
After the initial sync, data is always returned, but recent changes in the app may not appear immediately. These response headers indicate sync status:
| Header | Example | Description |
|---|---|---|
X-Last-Data-Change-At | 2024-01-28T14:23:45Z | Timestamp of last data modification |
X-Last-Data-Change-Rev | r1234 | Revision counter. Compare values to detect changes. |
X-Sync-In-Progress | false | If true, the response is valid but more changes may follow shortly. |
Write Operations
Every write endpoint — create, patch, delete, on both flavors and both protocols — answers the same envelope:
{
"summary": { "total": 2, "succeeded": 1, "clientErrors": 1,
"serverErrors": 0, "documentsWritten": 1 },
"results": [ { "inputIndex": 0, "id": "…", "success": true, … },
{ "inputIndex": 1, "id": "…", "success": false,
"error": "…", "errorType": "client_error", "fields": ["name"] } ]
}
- Batches are not atomic: each item is processed independently, so a single request can partially succeed. Batch maxima differ per endpoint and are kept deliberately small — the spec documents each (single-item creates take one object, not an array).
- Items are independent: a failed item never blocks its neighbours.
Each result row carries
inputIndex— the 0-based position of the item it answers — as the uniform correlation key. errorTypeisclient_error(fix your input, do not retry as-is) orserver_error(retryable);fieldsnames the input fields a failure is attributable to.documentsWrittencounts the documents the call actually wrote — deduplicated, outcome-confirmed, and independent of item success. It is NOT a copy ofsucceeded: an item whose fields already hold the sent values succeeds without writing (so a retried patch or delete answers 0), and one item can write several documents (a transfer's mirror, a rewritten pairing target).- REST status codes:
200all succeeded,207mixed,400/500all failed. REST batch patches also accept?validation=strict: any per-item validation error aborts the whole batch with400, nothing is written, and unprocessed items report"not executed". - Duplicate ids: two patch items addressing one document is ambiguous, so
every occurrence fails. Deletes are the exception — a repeated or already-deleted id is
idempotent success (with
documentsWrittenhonestly reporting what this call removed).
Agent Hints
Advisory, typed notes for AI agents, carried in an agentHints array. On REST,
enable with agentHints=true; on MCP they are always on. Each hint has a stable
type, a severity (info/warning/instruction),
human-readable text, and structured data. Examples:
| Type | When |
|---|---|
pagination.has_more | More results are available than returned |
result.partial_match | Some requested ids were not found |
result.empty | No records match the filters |
transfer.mirror_failed | A paired transfer's mirror could not be written |
category.defaulted_unknown | Records created without a category defaulted to Unknown |
budget.spent_netted | Income-signed records netted a budget's spent to 0 |
The full registry — every type, its severity, data fields and emitting tools — is served to
MCP clients as the reference://agent-hints resource and via
get_client_profile help: ["agent-hints"]. Hint types are
stable and safe to branch on; hint text is not.
Report a Bug
- Open Settings → Help in the Wallet web app (Board: Settings → Help) and click Go to Help Center.
- Click Support and Feedback.
- Select Report a Bug.
- Click Submit a request.
- Complete the report form.
When filling the form
- Issue type: Bug
- Subject: prefix with
REST API:orMCP:for faster routing to the correct team. - Description: provide a thorough description. When available, include:
- Request URI (e.g.
PATCH /v1/api/records) or MCP tool name X-Correlation-Idresponse header- Error response body
- Request URI (e.g.