Download OpenAPI specification:
An API for a shared Book — a financial ledger for one person or small
business, backed by a Clerk Organization so it can have collaborators.
A Book owns a set of ledger-api accounts and exposes a simplified,
type-aware transaction model (expense/income/transfer) so callers
never have to think in raw double-entry debits and credits.
Every route acts on the caller's active Clerk Organization: the Book
is always the verified JWT's org_id claim, never a URL or body
parameter. There is no Book-ID parameter anywhere to get an
authorization check wrong on.
Authenticate with a Clerk session token, issued against the books-api
JWT template (org claims enabled), sent as Authorization: Bearer <token>.
See books-api-plan.md and docs/projects/books-api/design.md in the
operations repo for the full domain design this implements.
Provisions books-api-plan.md's 15-account default chart of accounts against ledger-api. Not an upsert — fails with 422 if a Book already exists for this organization.
| currency required | string ISO 4217, e.g. |
{- "currency": "USD"
}{- "book": {
- "currency": "USD",
- "org_id": "string",
- "chart_version": 0,
- "created_at": "2019-08-24T14:15:22Z"
}, - "accounts": [
- {
- "id": "side-hustle",
- "display_name": "string",
- "type": "asset",
- "archived": true,
- "balance": 0,
- "created_at": "2019-08-24T14:15:22Z"
}
]
}| id required | string Slug — lowercase letters, numbers, and hyphens only. |
| display_name required | string |
| type required | string (AccountType) Enum: "asset" "liability" "income" "expense" |
{- "id": "side-hustle",
- "display_name": "string",
- "type": "asset"
}{- "id": "side-hustle",
- "display_name": "string",
- "type": "asset",
- "archived": true,
- "balance": 0,
- "created_at": "2019-08-24T14:15:22Z"
}books-api metadata only — never touches ledger-api. ledger-api's own account name is treated as immutable once created.
| id required | string An account/category's slug (e.g. |
| display_name | string |
| archived | boolean |
{- "display_name": "string",
- "archived": true
}{- "id": "side-hustle",
- "display_name": "string",
- "type": "asset",
- "archived": true,
- "balance": 0,
- "created_at": "2019-08-24T14:15:22Z"
}| limit | integer >= 1 Default: 50 |
{- "items": [
- {
- "id": "string",
- "type": "expense",
- "description": "string",
- "voids": "string",
- "voided_by": "string",
- "created_at": "2019-08-24T14:15:22Z"
}
]
}type picks how the signed ledger-api entries are derived — see books-api-plan.md 1.4. id is required and doubles as ledger-api's idempotency key: a retried POST with the same id returns the original, 200, never a duplicate post.
| id required | string Client-supplied — also used as ledger-api's idempotency key. |
| type required | string (TransactionType) Enum: "expense" "income" "transfer" |
| date | string <date> Defaults to today (UTC) if omitted. |
| description | string |
| source_account_id | string expense, transfer |
| destination_account_id | string income, transfer |
| category_id | string income, or expense without splits |
| amount | integer Positive, minor units. Required unless splits is used (expense). |
Array of objects (Split) expense only — multiple categories from one source account, must sum to amount if both are given. |
{- "id": "string",
- "type": "expense",
- "date": "2019-08-24",
- "description": "string",
- "source_account_id": "string",
- "destination_account_id": "string",
- "category_id": "string",
- "amount": 0,
- "splits": [
- {
- "category_id": "string",
- "amount": 0
}
]
}{- "id": "string",
- "type": "expense",
- "description": "string",
- "voids": "string",
- "voided_by": "string",
- "effective_date": "2019-08-24",
- "created_at": "2019-08-24T14:15:22Z",
- "entries": [
- {
- "account_id": "string",
- "amount": 0,
- "effective_date": "2019-08-24"
}
]
}| id required | string |
{- "id": "string",
- "type": "expense",
- "description": "string",
- "voids": "string",
- "voided_by": "string",
- "effective_date": "2019-08-24",
- "created_at": "2019-08-24T14:15:22Z",
- "entries": [
- {
- "account_id": "string",
- "amount": 0,
- "effective_date": "2019-08-24"
}
]
}Posts a new, equal-and-opposite transaction and links the two records — books-api-plan.md 1.5's "void, not edit" rule. No in-place edit exists; correcting a mistake means voiding the original and recording a new one.
| id required | string |
{- "id": "string",
- "type": "expense",
- "description": "string",
- "voids": "string",
- "voided_by": "string",
- "effective_date": "2019-08-24",
- "created_at": "2019-08-24T14:15:22Z",
- "entries": [
- {
- "account_id": "string",
- "amount": 0,
- "effective_date": "2019-08-24"
}
]
}