Ledga
POST/transactions

Create a new transaction (direct entries or trancode invocation)

Two mutually exclusive modes. Direct: supply entries[]. Template: supply transaction_code and transaction_code_params; the server validates params against the code's params_schema and materialises its entries. Sending both returns 422. Posting is asynchronous: the 202 body carries the id; GET /transactions/{id} returns the posted record.

Request bodyrequired

FieldTypeDescription
effective_daterequired string
date
Transaction effective date
descriptionrequired string
reference string External reference number
layer string
enum: settled | pending | encumbrance · default: "settled"
Case-insensitive on the request side; values like Settled or SETTLED are normalised to canonical lowercase before validation. Responses always render the canonical lowercase form.
journal_id string
uuid · nullable
correlation_id string
nullable
Group related transactions. If omitted but correlation_source_id is given, defaults to the source transaction's group handle (its correlation_id, else its id).
correlation_type string
max length: 50 · nullable
Correlation classifier (e.g. invoice, refund, reschedule). Paired with correlation_source_id — supply both or neither.
correlation_source_id string
uuid · nullable
Optional predecessor transaction (same ledger) to link to. Creates a Correlation pair row (source = this id, target = the new transaction) classified by correlation_type — e.g. a reschedule replacement pointing at its voided original.
idempotency_keyrequired string Unique key to prevent duplicate transactions
metadata object
nullable
attributes object
nullable
Optional searchable business dimensions — a flat map of key => value string pairs (e.g. {"customer_id": "C-123", "loan_id": "L-42"}). Applies to both posting modes. Keys must be lowercase snake_case (max 64 chars) and not shadow a reserved field; values are strings (max 128 chars). Subject to per-transaction (default 20) and per-tenant distinct-key caps, and, when the tenant runs strict mode, must be declared in the attribute catalog first — a violation returns 422 with an ATTRIBUTE_* code. Written atomically with the transaction and immutable thereafter.
entries object[] Mode 1 only. Double-entry transaction entries (must balance after server-side resolution). Mutually exclusive with transaction_code.
entries[].account_code string Account code (alternative to account_id)
entries[].account_id string
uuid
Account UUID (alternative to account_code)
entries[].typerequired string
enum: debit | credit
entries[].amountrequired string Amount in major units (e.g., dollars)
entries[].description string
nullable
entries[].metadata object
nullable
transaction_code string
max length: 50
Mode 2 only. Code of an active trancode in this ledger. Must be paired with transaction_code_params. Mutually exclusive with entries.
transaction_code_params object Mode 2 only. Parameter map keyed by parameter name as declared in the trancode's params_schema. Values are substituted into the template (account selectors and amount expressions) at materialisation time.

Responses

202Transaction accepted and processing
{
  "success": true,
  "data": {
    "id": "01997c1e-4d2a-7c3e-9a1b-2f0e8c6d4b5a",
    "status": "pending",
    "idempotency_key": "string",
    "correlation_id": "string",
    "message": "string"
  }
}
400Validation error
{
  "success": false,
  "message": "Validation failed",
  "code": "VALIDATION_ERROR"
}
401Unauthenticated
{
  "success": false,
  "message": "Validation failed",
  "code": "VALIDATION_ERROR"
}
403Forbidden
{
  "success": false,
  "message": "Validation failed",
  "code": "VALIDATION_ERROR"
}
409Idempotency key conflict
{
  "success": false,
  "message": "Validation failed",
  "code": "VALIDATION_ERROR"
}
503Idempotency service unavailable (code SERVICE_UNAVAILABLE) — fail-closed with a Retry-After header; nothing is written
{
  "success": false,
  "message": "Validation failed",
  "code": "VALIDATION_ERROR"
}

Examples

curl -X POST https://ledga.io/api/v1/transactions \
  -H "Authorization: Bearer sk_xxxxxxxx_your_secret" \
  -H "Content-Type: application/json" \
  -d '{
  "effective_date": "2026-01-15",
  "description": "Invoice INV-001 paid",
  "reference": "INV-001",
  "idempotency_key": "inv-001-payment",
  "entries": [
    {
      "account_code": "1000",
      "type": "debit",
      "amount": "500.00"
    },
    {
      "account_code": "4000",
      "type": "credit",
      "amount": "500.00"
    }
  ]
}'

← All endpoints