Developers

A REST API over the ledger, not around it.

The API posts through the same code path as the screens, with the same balance check, the same permission model and the same audit event. There is no back door that skips the accounting rules — which is the whole reason to have one.

Authentication

One bearer key, scoped and optionally pinned

Keys are shown once, stored hashed, and carry a capability subset. A key can be pinned to a single company, so an integration built for one set of books cannot reach another.

Request
curl https://your-host/api/v1/reports/trial-balance \
  -H "Authorization: Bearer iak_live_…" \
  -G -d from=2026-04-01 -d to=2027-03-31

# 200 OK
# X-API-Version: 1
# X-RateLimit-Limit: 600
# X-RateLimit-Remaining: 599
{
  "balanced": true,
  "difference": "0.0000",
  "rows": [ … ]
}

Surface

What is exposed today

Deliberately small. Every endpoint here is covered by tests that exercise it over HTTP with a real key, including the failure cases. A scope is a capability string in namespace:verb form — the same text you tick when you create a key, because a key holds capabilities rather than a separate set of API-only names.

Public API endpoints and their required scopes
MethodPathScopeNotes
GET/api/v1/companiescompany:viewCompanies the key may see.
GET/api/v1/accountsaccount:viewChart of accounts, with balances.
GET/api/v1/partiesparty:viewCustomers and suppliers.
GET/api/v1/vouchersvoucher:viewDay book, filtered and paged.
POST/api/v1/vouchersvoucher:postPost a balanced voucher. Idempotent.
GET/api/v1/reports/trial-balanceaccounting:reportDerived, never cached.
GET/api/v1/openapi—The OpenAPI 3.1 document. No key required.

Details

The things that bite

What happens if I retry a POST?
Send an Idempotency-Key header and a retry returns the original result rather than posting a second voucher. Financial writes are the one place where "just try again" has to be safe, so the key is stored with the response and replayed on a repeat.
Can a key do more than the person who made it?
No. A key carries a subset of its creator’s capabilities and is validated against that subset on every request. Requesting a scope the creator lacks fails at creation time, not at use time.
How is the API versioned?
In the path. /api/v1 will keep its response shapes; anything that changes them becomes /api/v2. Every response carries an API version header so a client can assert what it is talking to.
What are the rate limits?
Per key, reported on every response in the standard headers — limit, remaining and reset. A client that reads them never has to guess, and a 429 tells you when to come back rather than merely that you were early.

Build against real books.

Create an account, generate a key with only the scopes you need, and post your first voucher over HTTP.

Developers · Falcon