API overview
Authentication, the main endpoints, request and response shapes, and error handling.
Authentication
The API speaks JSON over HTTP. With server.secure: true, which the example config sets, every request except /health needs an X-LedgerForge-Key header. The master secret (server.secret_key) has deployment-wide administrator power: use it to provision scoped keys, and give applications and agents those instead. /metrics uses a separate bearer token. Keep the API behind TLS.
$ curl -s -X POST http://127.0.0.1:5001/transactions \ -H "X-LedgerForge-Key: $LEDGERFORGE_KEY" \ -H 'Content-Type: application/json' \ -d @transfer.jsonMain endpoints
| Endpoint | Purpose |
|---|---|
POST /ledgers, GET /ledgers/:id | Create and read ledgers. |
POST /balances, GET /balances/:id | Create and read balances, including counters and inflight components. |
GET /balances/:id/at, POST /balances-snapshots | Read a balance at a point in time and take snapshots. |
POST /transactions | Record a transfer, split transfer, inflight hold or preview. |
POST /transactions/bulk | Submit a batch with explicit atomic or asynchronous behaviour. |
GET /transactions/:id, GET /transactions/reference/:reference | Read a transaction by ID or by its business reference. |
PUT /transactions/inflight/:txID | Commit (fully or partly) or void an inflight hold. |
POST /refund-transaction/:id | Create a linked reversal of an APPLIED transaction. |
POST /api-keys, GET /api-keys, DELETE /api-keys/:id | Create, list and revoke scoped API keys. |
PUT /policies/:api_key_id, GET /policies/effective | Set a key's spending policy and inspect effective rules and capacity. |
GET /approvals, POST /approvals/:id/approve, POST /approvals/:id/reject | Review policy holds with an independent key. |
POST /hooks, GET /hooks | Register and list transaction hooks. |
POST /identities, POST /reconciliation/upload | Identities, and reconciliation against external records. |
GET /health | Public health check. |
The route list lives in api/api.go, which also covers filters, identity tokenisation, balance monitors, lineage, search and metadata updates.
Recording a transaction
{ "source": "bln_e0f81b15-bd0a-43c5-9e84-7fd4394192e8", "destination": "bln_df56a248-7d7e-4c0c-8fbf-a5215c87b603", "currency": "USD", "precise_amount": 1250, "precision": 100, "reference": "order-1042", "description": "Order 1042", "skip_queue": true, "allow_overdraft": true, "overdraft_limit": 12.5}{ "rate": 0, "precise_amount": 1250, "amount": 12.5, "amount_string": "12.5", "precision": 100, "overdraft_limit": 12.5, "transaction_id": "txn_c493a7e3-ac39-4456-90c3-ac43f00c5e0d", "parent_transaction": "", "source": "bln_e0f81b15-bd0a-43c5-9e84-7fd4394192e8", "destination": "bln_df56a248-7d7e-4c0c-8fbf-a5215c87b603", "reference": "order-1042", "currency": "USD", "description": "Order 1042", "status": "APPLIED", "hash": "9b7d7ad924e2e626055e3b33edcf194142e3fcd562de1807dd738d9afd7c1f87", "allow_overdraft": true, "inflight": false, "skip_queue": true, "atomic": false, "created_at": "2026-10-10T05:54:45.691597464Z", "effective_date": "2026-10-10T05:54:45.691597464Z", "scheduled_for": "0001-01-01T00:00:00Z", "inflight_expiry_date": "0001-01-01T00:00:00Z", "inflight_commit_date": "0001-01-01T00:00:00Z", "meta_data": { "allow_overdraft": true }}Read status to learn the outcome. Without skip_queue the response is the accepted, QUEUED transaction; fetch it again later. A preview with dry_run: true returns 200 rather than 201 because nothing was created.
Numbers
Amounts and balance counters are JSON integers in units of the transaction's precision. JavaScript numbers can't represent every integer above 2^53 − 1, so use a JSON parser that preserves large integers and treat floating-point values as presentation only. Policy limits and MCP *_minor fields are integer strings.
Errors
Errors keep a compatible envelope with a stable code and a deliberate message. Internal failures return a generic message; SQL text, connection strings and driver errors are written to operator logs, not responses.
{ "error": "reference has already been used", "error_detail": { "code": "TXN_DUPLICATE_REFERENCE", "message": "reference has already been used" }}{"error": "spending policy denied transaction"}. Don't assume every endpoint wraps a failure identically.