On this page
Record transactions
Record a transaction batch
POST /ledger/v1/transactions
The request body is an array of 1–1000 transaction commands. Even a single transaction is sent as a one-element array.
Headers
| Header | Required | Notes |
|---|---|---|
X-Tenant-ID | yes | Tenant the transactions belong to |
X-Idempotency-Key | yes | Missing key → 400 VALIDATION_ERROR |
X-Correlation-ID | no | Optional UUID |
Request body
[{
"name": "Sales invoice #42",
"description": "July invoice for cust-001",
"documentReference": "INV-2026-0042",
"transactionDate": "2026-07-01",
"unit": "EUR",
"entries": [
{ "accountReference": "1500-receivables", "entryType": "DEBIT", "amountMinorUnits": 125000,
"lineDescription": "Invoice total incl. VAT",
"dimensions": { "CUSTOMER": "cust-001" } },
{ "accountReference": "3000-sales", "entryType": "CREDIT", "amountMinorUnits": 100000 },
{ "accountReference": "2700-vat-out", "entryType": "CREDIT", "amountMinorUnits": 25000 }
],
"dimensions": [
{ "dimensionType": "PROJECT", "valueReference": "0b9f3c1e-…" }
],
"applicationMetadata": { "source": "billing-service" }
}]
| Field | Type | Constraints |
|---|---|---|
name | string | required, ≤ 200 chars |
description | string | ≤ 2000 chars |
documentReference | string | ≤ 100 chars |
transactionDate | date | required, yyyy-MM-dd |
unit | string | required, ≤ 20 chars — a currency (EUR, JPY, …) or other registered unit (kgCO2e, hours, …) |
entries | array | required, minimum 2 entries |
entries[].accountReference | string | required, ≤ 50 chars |
entries[].amountMinorUnits | integer | required; signed, scaled by the unit (Amounts and units) — negative means “reduce this side” |
entries[].entryType | enum | required, DEBIT or CREDIT |
entries[].lineDescription | string | ≤ 500 chars |
entries[].dimensions | object | map of dimension type → value |
entries[].quantity | decimal | optional, ≥ 0 (e.g. shares) |
dimensions | array | block-level {dimensionType, valueReference} |
applicationMetadata | object | free-form |
enforceCapture | boolean | optional; enforce dimension-capture validation |
Every block must balance: the signed sum of DEBIT amounts must equal the signed sum of CREDIT amounts. See Negative amounts for what a negative entry means.
Response — 201 Created
Location: /ledger/v1/transactions/batch/{idempotencyKey}. The body is an array, one element per recorded transaction:
[{
"transactionId": "7d9e1a4c-90b2-4f7a-a9d3-2f6f6f1e0b7e",
"tenantId": "org-84120557",
"correlationId": "b2f1…",
"name": "Sales invoice #42",
"transactionDate": "2026-07-01",
"unit": "EUR",
"entryCount": 3,
"totalDebitMinorUnits": 125000,
"recordedAt": "2026-07-01T09:14:03.512Z"
}]
Errors
| Status | Code | Cause |
|---|---|---|
400 | UNBALANCED_TRANSACTION | Σ debits ≠ Σ credits |
400 | VALIDATION_ERROR | Missing idempotency key, empty batch, field violations |
409 | IDEMPOTENCY_CONFLICT | Key already used; violations carries existingTransactionId=<uuid> |
413 | BATCH_SIZE_EXCEEDED | More than 1000 transactions (or oversized payload) |
Correct a transaction
POST /ledger/v1/transactions/{transactionId}/corrections
Records a compensating reversal of the original block: every debit becomes a credit and vice versa. The original stays untouched — both blocks remain in the ledger.
Headers are the same as above (X-Idempotency-Key required).
Request body
{
"reason": "Invoice #42 was issued to the wrong customer",
"correctionDate": "2026-07-03",
"applicationMetadata": { "requestedBy": "ops" }
}
| Field | Type | Constraints |
|---|---|---|
reason | string | required, ≤ 2000 chars |
correctionDate | date | required, yyyy-MM-dd |
applicationMetadata | object | optional |
Response — 201 Created
Location: /ledger/v1/transactions/{correctionTransactionId}:
{
"correctionTransactionId": "4c1b…",
"originalTransactionId": "7d9e1a4c-…",
"tenantId": "org-84120557",
"correlationId": "b2f1…",
"reason": "Invoice #42 was issued to the wrong customer",
"correctionDate": "2026-07-03",
"unit": "EUR",
"entryCount": 3,
"totalDebits": 125000,
"timestamp": "2026-07-03T08:02:44.100Z"
}
Errors
| Status | Code | Cause |
|---|---|---|
400 | VALIDATION_ERROR | Missing reason/date, missing idempotency key |
404 | TRANSACTION_NOT_FOUND | Unknown transactionId |
409 | IDEMPOTENCY_CONFLICT | Key already used |