---
title: "Accounting API for developers: the whole ledger over REST"
description: "Ledgeriano's accounting API: post journal entries, manage accounts and pull reports over REST, with owner-managed keys, idempotency and signed webhooks."
canonical: https://ledgeriano.com/developers
language: en
publisher: "Ledgeriano"
updated: 2026-11-05
---

# Accounting API for developers: the whole ledger over REST

> Ledgeriano's accounting API: post journal entries, manage accounts and pull reports over REST, with owner-managed keys, idempotency and signed webhooks.

Ledgeriano's accounting API gives your code everything the dashboard can do for one business: accounts, journal entries, fiscal years, parties, exchange rates, financial reports, inventory and cost accounting, budgets and management accounting, webhooks and the audit trail. JSON in, JSON out, with an OpenAPI reference you can try in the browser.

- **REST**: JSON over HTTPS, OpenAPI documented
- **Bearer**: owner-managed API keys
- **120/min**: default rate limit per key
- **16**: webhook event types

Every business has its own keys; the key decides which business you are talking to.

Base URL

## From zero to a posted journal entry in three steps

### Create a key

As the business owner, open the business settings, create an API key and choose its abilities: **read**, or **read and write**. Copy it right away: the full key is shown only once.

### Make a read call

Send `GET /accounts` with `Authorization: Bearer lgr_live_…`. The response lists the chart of accounts of that business, and the headers show your remaining rate limit and credit balance.

### Post an entry

Send `POST /journal-entries` with balanced lines and an `Idempotency-Key`. Use account codes or ids, add `"status": "posted"` to post immediately, or leave it as a draft for review.

## Post a journal entry in curl, JavaScript or Python

The same request in three languages: a posted sales entry with a customer on the receivable line. Retrying with the same idempotency key returns the original entry instead of creating a second one.

Read accounts and reports

Copy

Copied

## API keys that only the owner can create, rotate and revoke

Send the key as a bearer token: `Authorization: Bearer lgr_live_…`. The `X-API-Key` header works too. Keys belong to one business, so an integration for three companies uses three keys, and a leaked key never exposes the other books.

A key with the **read** ability can call read endpoints. Anything that changes data needs **write**; without it the API answers `403`. Keys can have an expiry date, can be rotated (the old key stops working and a new one is issued with the same settings) and can be revoked at any time. Every call is logged with the key that made it.

| Resource | Endpoints | Notes |
| --- | --- | --- |
| Fiscal years | `GET` `POST` `/fiscal-years`, `GET` `PUT` `DELETE` `/fiscal-years/{id}`, `POST /{id}/close`, `POST /{id}/reopen` | Closing writes the closing and opening entries |
| Accounts | `/accounts` CRUD, `GET /accounts/{id}/balance`, `PUT /accounts/cost-behavior` | Chart of accounts of the current fiscal year; cost behaviour (fixed, variable, mixed) in bulk |
| Parties | `/parties` CRUD | Customers and suppliers |
| Cost centers | `/cost-centers` CRUD | Departments, branches |
| Projects | `/projects` CRUD | Jobs and contracts |
| Voucher types | `/voucher-types` CRUD | Codes such as SAL, PUR, PAY |
| Journal entries | `/journal-entries` CRUD, `POST /bulk-post`, `POST /{id}/post`, `POST /{id}/reverse`, `POST /{id}/duplicate`, `/{id}/attachments` | Drafts can be edited; posted entries are corrected by reversal |
| Exchange rates | `GET` `POST` `/exchange-rates`, `DELETE /exchange-rates/{id}` | Used when an entry has no rate of its own |
| Reports | `/reports/trial-balance`, `balance-sheet`, `income-statement`, `cash-flow`, `equity-changes`, `general-ledger`, `journal`, `party-balances`, `dashboard` | Same numbers as the dashboard |
| Inventory setup | `GET` `POST` `DELETE` `/inventory/setup` | Turns the inventory and costing module on or off and maps its accounts |
| Inventory master data | `/units`, `/warehouses`, `/item-categories`, `/items` CRUD | Valuation method per item: FIFO, weighted average, standard or specific identification |
| Lots and serials | `/lots` CRUD, `/inventory-reports/lot-balances`, `expiring-lots`, `lot-trace`, `serial-history` | FEFO allocation, backward and forward traceability |
| Stock documents | `/stock-documents` CRUD, `POST /{id}/post`, `POST /{id}/cancel` | Receipts, returns, issues, deliveries, transfers, adjustments, landed costs, write-downs |
| Stock counts | `/stock-counts`, `POST /{id}/complete`, `POST /{id}/cancel` | Completing a count posts the adjustment |
| Inventory reports | `/inventory-reports/on-hand`, `kardex`, `movement-summary`, `reconciliation`, `ageing`, `reorder` | Stock ledger reconciled with the general ledger |
| Production | `/boms` CRUD, `POST /boms/{id}/roll-up`, `/cost-center-rates`, `/production-orders` with `release`, `issue`, `receive`, `close`, `reopen`, `GET /{id}/cost-sheet` | Job order costing with standard cost roll-up |
| Labour and overhead | `/labor-entries`, `/overhead-applications`, `/overhead-allocations`, `/overhead-closings` (with `preview`) | Direct, step-down and reciprocal allocation |
| Process costing | `/process-runs` CRUD, `POST /{id}/post`, `POST /{id}/cancel` | Equivalent units, weighted average or FIFO |
| Costing reports | `/costing-reports/cogm`, `overhead`, `profitability`, `wip`, `variances` | Cost of goods manufactured and sold, variances |
| Scrap and direct costs | `POST /production-orders/{id}/scrap`, `GET /production-scraps`, `POST /production-scraps/{id}/cancel`, `GET` `POST` `/direct-costs`, `POST /direct-costs/{id}/cancel` | Normal and abnormal scrap, subcontracting and other direct costs |
| Planning | `GET` `POST` `/mrp`, `GET` `POST` `/capacity-load` | Multi-level BOM explosion, reorder suggestions, capacity vs normal hours |
| Budgets | `/budgets` CRUD, `PUT /{id}/lines`, `POST /{id}/lines/from-actuals`, `POST /{id}/lines/from-budget`, `POST /budgets/spread`, `POST /{id}/duplicate`, `approve`, `unapprove`, `archive`, `default`, `GET /budget-periods` | Monthly lines by account, cost center and project |
| Budget reports | `GET /budgets/{id}/vs-actual`, `GET /budgets/{id}/flexible` | Variances by section, account, cost center, project or month |
| Master budget plans | `/budget-plans` CRUD, `POST /{id}/compute`, `POST /{id}/generate-budget` | Operating and cash budgets, budgeted income statement |
| Management analyses | `/management/cvp`, `variable-costing`, `segments`, `ratios` | Break-even, absorption reconciliation, ROI and residual income, 19 ratios |
| Decisions and ABC | `POST /management/decisions/{type}`, `/abc-models` CRUD, `POST /abc-models/{id}/compute` | Make or buy, special order, keep or drop, sell or process further, limiting factor |
| Webhooks | `/webhooks` CRUD, `GET /{id}/deliveries`, `POST /{id}/test`, `POST /{id}/deliveries/{delivery}/redeliver` | Signed with HMAC SHA-256 |
| Audit logs | `GET /audit-logs` | Who did what, when, from where |

## Idempotency, errors, limits and credits

### Idempotency keys

Send `Idempotency-Key` (or `idempotency_key` in the body) when creating an entry. A retry with the same key returns the entry that already exists, with status 200 instead of 201, so a network timeout never books a sale twice.

### One error shape

Every error has a machine-readable `code`, a human-readable `message` and, for validation, `errors` keyed by field such as `lines.0.debit`.

### Rate limits

Each key may make 120 requests per minute by default. Watch `X-RateLimit-Limit` and `X-RateLimit-Remaining`; a `429` carries `retry_after` in seconds.

### Credits in headers

Each request costs the `api.call` price and actions add their own, such as `entry.create`. `X-Credits-Charged` and `X-Credits-Balance` show the cost and what is left; a `402` means the balance ran out.

Example error

- Status
- Meaning

- 401
- Missing, invalid, expired or revoked API key

- 402
- Not enough credits (`insufficient_credits`)

- 403
- The key lacks the `write` ability or the permission

- 404
- The resource does not exist in this business

- 409
- Conflicts with the current state, such as editing a posted entry or writing into a closed year

- 422
- Validation failed; see `errors` by field

- 423
- The business or the owner's account is suspended

- 429
- Rate limit reached; retry after `retry_after` seconds

## Signed webhooks for entries, accounts, parties, fiscal years and stock

Subscribe a URL to the events you need and Ledgeriano sends a JSON `POST` for each one. Every delivery carries `X-Webhook-Event`, a unique `X-Webhook-Delivery` id, `X-Webhook-Timestamp` and `X-Webhook-Signature`.

The signature is `sha256=` followed by the hex HMAC SHA-256 of `timestamp + "." + raw_body`, keyed with your webhook secret. Failed deliveries are retried up to 5 times with growing delays (30 seconds up to 30 minutes), and you can inspect, test and redeliver them through the API.

Events

- entry.created
- entry.updated
- entry.posted
- entry.reversed
- entry.deleted
- account.created
- account.updated
- account.deleted
- fiscal_year.created
- fiscal_year.closed
- party.created
- party.updated
- stock_document.posted
- stock_document.cancelled
- production_order.closed
- costing.run_posted

Verify the signature

A delivery

## Accounting API questions

### Is there a free way to test the accounting API?

Yes. New accounts get free credits. Create a business, generate a key and call the API; each request uses a small number of credits, shown in the `X-Credits-Charged` header.

### Can one API key access several businesses?

No. Each key belongs to exactly one business. That keeps integrations isolated: revoking one key never affects the others.

### How do I correct a posted entry through the API?

Call `POST /journal-entries/{id}/reverse`. Ledgeriano creates a posted reversal with debits and credits swapped and marks the original as reversed. Then post the corrected entry.

### Does the API support foreign currencies?

Yes. Send `currency_code` and `exchange_rate` on the entry, or omit the rate and Ledgeriano uses the latest rate stored under `/exchange-rates`.

### Where is the full endpoint reference?

The OpenAPI reference, rendered with Scalar, is at api.ledgeriano.com/docs/api. For a walkthrough with examples read the [accounting API guide](https://ledgeriano.com/guides/accounting-api).
