Response envelope
Successful tool calls return:
{ "ok": true, "data": { … } }
Failures return:
{ "ok": false, "error": { "code": "…", "message": "…", "details": { … } } }
Per-tool pages document the shape of data. Sidebar response examples are illustrative.
Unknown fields
Unknown request fields (including nested paths such as boxes[0].typo or alertSettings.foo) are rejected. They are not silently ignored.
- Tool HTTP status is typically 400
- Body:
{ "ok": false, "error": { "code": "invalid_argument", "message": "…", "details": { "fields": ["…"] } } } - MCP
tools/callreturns the sameerrorobject withisError: true
Budgets use baseCurrency; boxes, expenses, accounts, transactions, and investments use per-item currency. Values are ISO 4217 codes from the Currencies allow-list.
Idempotency
Create-style tools require a client key so a retry after a timeout does not insert twice (create_budget, create_box, create_expense, create_transaction, create_investment_group, create_investment, link_account, duplicate_budget, duplicate_box, duplicate_expense).
create_transactions uses a per-row idempotencyKey instead of a top-level key (same namespace as create_transaction). The batch counts as one write toward the rate limit.
| Situation | HTTP | error.code |
|---|---|---|
| Missing / invalid key | 400 | idempotency_key_invalid |
| Header and body key disagree | 400 | idempotency_key_mismatch |
| Same key, different body | 409 | idempotency_conflict |
| Same key still processing | 409 | idempotency_in_progress |
| Same key, same body (replay) | 200 | — (original data) |
Send Idempotency-Key on HTTP and/or idempotencyKey in the JSON / MCP arguments. Keys last about 24 hours. See Tools index.
Rate limits
Fixed minute windows. Each API token (liq_…) and each OAuth access token has its own read and write budget. API scripts and MCP sessions do not share one account-wide pool.
| Limit | Scope | Cap |
|---|---|---|
| Tool reads | Each token (PAT or OAuth access token) | 60 / minute |
| Tool writes | Each token (PAT or OAuth access token) | 60 / minute |
| Failed authentications | Each client IP | 20 / minute |
After 20 failed Bearer authentications from one IP in a minute, every request from that address receives 429 until the window ends, even with a valid token.
Inventory
| Resource | Cap |
|---|---|
Active API tokens (liq_… PATs) | 10 / user |
Create tokens in the app (Connections → API tokens); an 11th active token is rejected there. Plan Analysis / Transactions Analysis daily caps are separate (Pro and Ultra 10/day) and not exposed on this API.
Creation caps
Hitting a collection cap returns resource_limit.
| Resource | Cap |
|---|---|
| Owned budgets (Ultra Tools / MCP) | 20 |
| Boxes per budget | 30 |
| Expenses per box | 100 |
Nested create_budget tree items | 3000 |
create_transactions rows per call | 100 |
| Linked accounts per budget | 30 |
| Manual transactions per account | 1000 |
| Manual investment groups per budget | 30 |
| Manual holdings per investment group | 1000 |
Field caps
Out-of-range values return invalid_argument.
| Field | Cap |
|---|---|
| Names, descriptions, city, group, code, isin | 100 characters |
| Money amounts (boxes, expenses, balances, …) | 0 … 1,000,000 |
Manual transaction amount | ±1,000,000 |
Budget monthlyNetIncome | 0 … 3,000,000,000 |
search_help returns at most 10 hits (limit default 5).
On limit
- HTTP 429
- Header
Retry-After: <seconds> - JSON body includes
error/retryAfterSeconds(and oftencode: assistant_rate_limited)
On success
Response may include:
RateLimit-LimitRateLimit-RemainingRateLimit-Reset(unix seconds)
Clients must honor Retry-After and avoid tight retry loops.