API Reference
Base URL: https://api.ledger.example.com/v1
The Ledger API is a JSON-over-HTTPS interface for reading and writing accounts, transactions, and invoices. All requests and responses use application/json unless noted otherwise. Timestamps are ISO 8601 in UTC. Monetary amounts are integers expressed in the smallest currency unit (for example, cents).
sk_test_. Test data never touches live balances.
Authentication
Authenticate every request with a secret key sent as a Bearer token in the Authorization header.
curl https://api.ledger.example.com/v1/accounts \
-H "Authorization: Bearer sk_test_4eC39HqLyjWDarjtT1zdp7dc"
Keep secret keys on the server. Never embed them in browser or mobile code.
Errors
Errors return a non-2xx status code and a JSON body describing the problem.
{
"error": {
"type": "invalid_request",
"code": "missing_field",
"message": "The field 'currency' is required.",
"param": "currency"
}
}
| Status | Meaning |
|---|---|
| 400 | Malformed or invalid request body |
| 401 | Missing or invalid API key |
| 403 | Key lacks permission for this resource |
| 404 | Resource not found |
| 409 | Conflict, such as a duplicate idempotency key |
| 429 | Rate limit exceeded; retry after the Retry-After interval |
| 500 | Something went wrong on our side |
Pagination
List endpoints are cursor-paginated. Pass limit (1 to 100, default 20) and the starting_after cursor from the previous page's last item.
{
"data": [ ... ],
"has_more": true,
"next_cursor": "txn_01HZX8K3Q2"
}
Accounts
An account holds a balance in a single currency.
Returns a paginated list of accounts, newest first.
Returns a single account by its identifier.
| Parameter | Type | Description |
|---|---|---|
name | string | Display name for the account. Required. |
currency | string | ISO 4217 code, such as USD. Required. |
metadata | object | Up to 20 string key-value pairs. |
{
"id": "acc_01HZX7P4M9",
"object": "account",
"name": "Operating",
"currency": "USD",
"balance": 0,
"created": "2024-05-14T09:21:07Z",
"metadata": {}
}
Transactions
Transactions move funds between accounts. Amounts are positive integers; direction is set by type.
Supports filtering with account, type, and created_after query parameters.
| Parameter | Type | Description |
|---|---|---|
account | string | Source account ID. Required. |
amount | integer | Amount in the smallest currency unit. Required. |
type | string | credit or debit. Required. |
description | string | Shown on statements. Optional. |
Send an Idempotency-Key header on every create request so retries do not double-post.
Invoices
Invoices request payment from a customer. They move through draft, open, paid, and void.
Only draft invoices can be edited. Send only the fields you want to change.
Voids an open invoice. The record is retained for auditing.
Webhooks
Register an HTTPS endpoint to receive events as they happen. Each delivery is signed in the Ledger-Signature header so you can verify it came from us.
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(header)
);
}
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, header)