Wallet logo Wallet API Reference

Base URL: https://rest.budgetbakers.com/wallet

Full Specification: OpenAPI (Swagger UI) — all endpoints, schemas, and interactive testing

Authentication

All endpoints require an API token, obtained in the Web app (Premium plan required):

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

API uses the Token Bucket Rate limiting algorithm, which allows short bursts of requests while enforcing an average rate over time.

Header Example Description
X-RateLimit-Limit 500 Maximum request capacity
X-RateLimit-Remaining 487 Remaining request capacity

Query Filter Prefixes

Some endpoints have query parameters that require filter prefixes in format: prefix.value

Example: amount=gte.100 → amount ≥ 100

Text Filters

Use prefix operators to filter text fields (e.g. note, payee fields).

Prefix Meaning Example
eq. Exact match payee=eq.Amazon
contains. Contains substring (case-sensitive) note=contains.Bill
contains-i. Contains substring (case-insensitive) note=contains-i.grocery

Text filters can be specified up to 2 times for AND logic. E.g. note=contains-i.grocery&note=contains-i.market

Range Filters

Used for numeric properties (e.g. amount) and datetime fields (recordDate, createdAt).

Prefix Meaning Example (numeric) Example (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. Greater than or equal amount=gte.100 createdAt=gte.2024-01-01T00:00:00Z
lt. Less than amount=lt.500 createdAt=lt.2024-12-31T23:59:59Z
lte. Less than or equal amount=lte.500 createdAt=lte.2024-12-31T23:59:59Z
Date-only values

When date-only values (no time component) are provided, whole-day (in UTC) semantics apply.:

Filter Equivalent Meaning
gt.2025-01-14 gte.2025-01-15T00:00:00Z Starting from Jan 15
gte.2025-01-14 gte.2025-01-14T00:00:00Z Starting 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 Up to and including Jan 15
eq.2025-01-13 gte.2025-01-13T00:00:00Z&lt.2025-01-14T00:00:00Z Entire day of Jan 13

Range filters support up to 2 conditions (AND logic) using repeated parameters:

Comma-separated syntax is also accepted: amount=gte.100,lte.500

Data Synchronization

User data is synchronized from Wallet app. Changes made in the app may not appear immediately via API.

Initial Sync

Synchronization begins when you generate your first API key. Until the initial sync completes, requests return 409 Conflict:

{
  "error": "init_sync_in_progress",
  "message": "Data synchronization in progress. Please retry later.",
  "retry_after_minutes": 5
}

Ongoing Sync

After initial sync, data is always returned, but recent changes in user data 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, response is valid but more changes may follow shortly.

Agent Hints

Advisory information for AI agents. Hints can provide context about results, pagination, and rate limits.

Enable: Add agentHints=true to any request.

Type Severity When Generated
pagination.has_more instruction More results available (includes next page URL)
result.partial_match info Some requested IDs not found
result.empty info No records match filters
param.inferred info Filtering date bound auto-inferred
(relevant to recordDate in /records)
rate_limit.warning warning Approaching rate limit

Write Operations

Coming soon. Write endpoints (POST, PATCH, DELETE) are currently in development and will be available in a future release. The documentation below describes the planned behavior and constraints.

Batch Semantics & Partial Success

Most write endpoints accept arrays of items in a single request. Batch sizes are intentionally small to keep operations predictable.

Operation Batch? Max items
POST /records Yes (array) 20
POST /accounts No (single item) 1
POST /budgets No (single item) 1
POST /categories/custom No (single item) 1
PATCH /records, /accounts, /categories Yes (array) 10
DELETE /v1/api/{type} Yes (array of IDs) 10

Due to technical limitations, batch operations are not atomic. Each item is processed independently — a single request can partially succeed. When a batch contains mixed results, the response uses HTTP 207:

Field Description
summary.total Total items in the request
summary.succeeded Number of items that succeeded
summary.clientErrors Items that failed due to invalid input (your fault)
summary.serverErrors Items that failed due to internal errors (our fault)
results[] Per-item results with success, error, and errorType (client_error or server_error)

If all items succeed, the response is HTTP 200. Use validation=strict in PATCH requests to reject unknown fields instead of silently ignoring them.

Records

Creating Records

POST /records — up to 20 records per request. Maximum 20,000 records per user (includes records created in mobile/web apps).

Field Required Validation
accountId Yes Must reference an existing account. Cannot be a bank-synced account.
amount Yes Non-zero. DECIMAL(19,2) precision. Negative = expense, positive = income. recordType is auto-derived from the sign.
recordDate Yes ISO 8601 format. Cannot be more than 24 hours in the future or more than 10 years in the past.
paymentType Yes One of: cash, debit_card, credit_card, transfer, voucher, mobile_payment, web_payment
categoryId No Any category UUID from GET /categories. If omitted, auto-assigned to Unknown Income or Unknown Expense based on amount sign. Internal system categories cannot be assigned (see Categories).
recordState No Default: cleared. Also: reconciled, uncleared
labelIds No Array of label UUIDs. Each must exist.
note No Max 255 characters
counterParty No Max 255 characters

Transfer records cannot be created via the API. Transfer pairs created in the mobile app are partially patchable (metadata only) and must be deleted as a pair.

Patching Records

PATCH /records — up to 10 records per request. At least one field must be provided.

Field Patchable Notes
categoryId Yes Category UUID from GET /categories.
labelIds Yes Replaces all labels. Use empty array [] to clear.
note Yes Max 255 characters
counterParty Yes Max 255 characters
paymentType Yes Same enum as create
recordState Yes* Locked on bank-synced and transfer records
recordDate Yes* Locked on bank-synced and transfer records
amount Yes* Locked on bank-synced and transfer records.
accountId No Immutable after creation

* Fields marked with * are locked on bank-synced accounts and transfer records. Attempting to patch them returns a client_error. Metadata fields (note, labels, category, paymentType, counterParty) can always be patched.

Accounts

Creating Accounts

POST /accounts — single account per request. Maximum 50 accounts per user (includes accounts created in mobile/web apps).

Field Required Validation
name Yes Max 80 characters
accountType Yes One of: General, Cash, CurrentAccount, SavingAccount, Insurance. Other types (CreditCard, Investment, Loan, etc.) are read-only and managed by the mobile app.
currencyCode Yes ISO 4217 fiat currency code (e.g. USD, EUR). Immutable after creation.
initialBalance Yes DECIMAL(19,2) precision
color No One of 16 supported colors. Randomly assigned if omitted.

Patching Accounts

PATCH /accounts — up to 10 per request.

Field Patchable Notes
name Yes Max 80 characters
archived Yes Boolean
color Yes one of the 16 supported colors
initialBalance Yes DECIMAL(19,2). Also recalculates the base-currency amount.
excludeFromStats Yes Boolean
bankAccountNumber Yes Max 80 characters. Empty string clears the value.
accountType No Immutable after creation
currencyCode No Immutable after creation

Bank-synced accounts cannot be patched via the API. Use the mobile app to manage them.

Account deletion is not currently supported via the API.

Categories

Custom Categories

Custom categories are always derived from a base (system) category via parentId. Create them for highly specific purposes that don't fit into existing base categories (e.g. "Subscriptions" under "Entertainment").


POST /categories/custom — single category per request. Maximum 50 custom categories per user (includes categories created in mobile/web apps).

Field Required Validation
name Yes Max 80 characters. Must be unique (case-insensitive) across all categories.
parentId Yes UUID of a system (base) category. Use GET /categories to find valid parents. Internal system categories cannot be used as parents (see below).
color No One of 16 supported colors. Defaults to parent's color.
cardinality No Wallet: must / need / want. Defaults to parent's value.

Restricted System Categories

The following internal system categories cannot be assigned to records and cannot be used as parentId for custom categories:

Name UUID
Debt 5c5c4e20-00c8-8000-8000-000000000000
Transfer 5c5c4e21-00c8-8000-8000-000000000000
Shopping List 5c5c4e22-00c8-8000-8000-000000000000
Uncategorized 5c5c4e23-00c8-8000-8000-000000000000

Patching Categories

PATCH /categories — up to 10 per request. Works on both base and custom categories.

Field Patchable Notes
name Yes Max 80 characters. Sets customName=true. Cannot be used with resetName.
resetName Yes Boolean. Resets name to system default. Only works on base (non-custom) categories. Cannot be used with name.
color Yes one of the 16 supported colors
cardinality Yes Use "none" to clear

Deleting categories: Only custom categories can be deleted. The category must have no references from records, budgets, standing orders, or record rules. Use GET /{type}/references?id=... to check before deleting.

Budgets

Creating Budgets

POST /budgets — single budget per request. Maximum 50 budgets per user (includes budgets created in mobile/web apps).

Field Required Validation
name Yes Max 80 characters
currencyCode Yes ISO 4217 fiat currency code. Immutable after creation.
type Yes BUDGET_INTERVAL_WEEK, BUDGET_INTERVAL_MONTH, BUDGET_INTERVAL_YEAR, or BUDGET_CUSTOM. Immutable after creation.
limit Yes Budget spending limit. Must be > 0. DECIMAL(19,2) precision.
startDate / endDate BUDGET_CUSTOM only YYYY-MM-DD format. endDate must be ≥ startDate. Not accepted for interval types.
categoryIds No Array of category UUIDs to track. Both base and custom category IDs accepted. If left empty, all are tracked.
accountIds No Array of account UUIDs. Limits budget tracking to these accounts. If left empty, all are tracked.
labelIds No Array of label UUIDs. If left empty, all are tracked.

Patching budgets is currently disabled.

Deleting budgets is supported. Budgets have no child references, so they can always be deleted.

Deleting Entities

DELETE /v1/api/{type} — up to 10 IDs per request.

Type Deletable Restrictions
records Yes Not on bank-synced accounts. Transfer pairs must both be in the same batch. No active standing order references.
budgets Yes None — always deletable
standing-orders Yes None — always deletable
record-rules Yes None — always deletable
categories Custom only Must have no references. Use GET /{type}/references to check.
accounts No Not supported via API
labels No Not supported via API
goals No Not supported via API

Pre-check references before deleting categories and records: GET /v1/api/{type}/references?id=uuid1,uuid2 (max 10 IDs). The response shows which entities reference the given IDs. If references exist, the delete will fail with a client_error for that item.