Skip to content
Ledger by RODMENA
Menu

Product

One ledger for money, credits and stock

Ledger is a hosted double-entry ledger with an API. Your systems post movements, and the ledger keeps books that always balance, never forget and can be proved at any moment.

What you get

Seven things the API does

Asset types and accounts

Define a thing you count, such as a currency, a credit or a stock unit, and give it its own precision. Then open accounts for it. Every account declares the lowest balance it may reach.

Balanced transactions

A transaction lists where value comes from and where it goes. It is accepted whole or refused whole. There is no partial write.

Reserve now, settle later

Set money or stock aside without moving it. Complete the hold when the sale goes through, or release it yourself. Unfinished holds expire on a schedule you choose.

Balances, past and present

Read what is posted and what is available now, or the balance as it stood at an earlier moment. Statements are paged, and a page you have already read will not shift underneath you.

Safe retries

Every write carries a key you derive from your own record. Send it twice and the second call returns the first answer without moving anything again.

Ledgers for your own clients

A client gets an isolated ledger under your account, along with their own accounts, records and keys. You suspend and restore them through the API.

A machine-readable contract

The full API is published as an OpenAPI document, and a plain-text contract written for software agents is served beside it.

The ledger model

What happens when you post a transaction

  1. 1. Request

    Your system posts a transaction with a key of its own choosing.

  2. 2. Checks

    Balance, floors, account state and your key are all verified together, under lock.

  3. 3. Journal

    The entries are written permanently, or nothing is written at all.

  4. 4. Balances

    Posted and available balances update in the same step. A background check keeps proving they add up.

A write is accepted whole or refused whole. The journal is the record, and balances are derived from it and continuously checked against it.

A walk through the API

Eight steps, each captured from a running instance

The guide shows every request and response. The runnable tour in the ledger repository performs them against a live tenant.

  1. Step 1

    Authenticate

    One credential, scoped to your tenant. Its role decides whether it can read, post, administer, or manage clients.

  2. Step 2

    Define assets and accounts

    Create an asset type such as GBP with two decimal places, a control account for money entering the system, and customer accounts floored at zero.

  3. Step 3

    Move value

    Post a transfer of 100.00 from the control account to a customer. The response shows the available balance of both accounts after the move.

  4. Step 4

    Retry safely

    Send the same request again with the same key, and the original answer comes back without the money moving twice. Send a different body under the same key and it is refused.

  5. Step 5

    Read the books back

    The balance now, the statement page by page, and the transaction itself.

  6. Step 6

    Reserve and settle

    Place a hold of 25.00, then complete one hold and release another. Anything you leave unresolved is released when it expires.

  7. Step 7

    Handle refusals

    An overdraft attempt, an unbalanced request and an invalid timestamp all return a clear code that names the field. Retry only the temporary ones.

  8. Step 8

    See isolation at work

    Ask for a record with another tenant’s credential and it does not exist. Nothing in the answer confirms that the record is there.

Step 3 and 4: a transfer, and the same request sent twice
POST /v1/transactions
Idempotency-Key: payout-2026-09-05-0001
Content-Type: application/json

{
  "description": "welcome credit",
  "entries": [
    { "account_id": "<control account>",  "direction": "debit",  "amount": "100.00" },
    { "account_id": "<customer account>", "direction": "credit", "amount": "100.00" }
  ]
}

201 Created                     (a second identical request answers
Idempotent-Replay: true   <---   with the same body and this header)
Money and goods move together, or not at all
# money and goods in one write — or neither
POST /v1/transactions
{
  "description": "sale: 2 widgets for 50.00",
  "entries": [
    { "account_id": cash,     "direction": "debit",  "amount": "50.00" },
    { "account_id": customer, "direction": "credit", "amount": "50.00" },
    { "account_id": stock,    "direction": "credit", "amount": "2" },
    { "account_id": shipped,  "direction": "debit",  "amount": "2" }
  ]
}

# unbalance either asset and the whole write is refused:
# 422 UNBALANCED_TRANSACTION
Step 7: every refusal is the same shape, and says how to react
{
  "error": {
    "code": "INSUFFICIENT_AVAILABLE",
    "message": "insufficient available",
    "details": [{
      "account_id": "019fdfe1-…",
      "available_minor": "7500",
      "balance_floor_minor": "0"
    }]
  }
}

# how to react, by class
# 409 + Retry-After -> wait, then retry with the SAME key
# 422 / 404 / 403   -> a fact about your request; fix it or surface it
# 5xx               -> temporary; your key is not consumed

Read the full walk-through in the getting-started guide.

Implementation path

From first key to reconciled reporting

  1. 1

    Get a key

    Request access, and we provision a tenant and mint your first key. A partner key lets you create ledgers for your own clients.

  2. 2

    Model your books

    Choose asset types and precision, then decide which accounts are customer-facing, floored at zero, and which are control accounts.

  3. 3

    Post from your system of record

    Derive a request key from your own document, such as an order or a statement line. A retry then cannot double-post.

  4. 4

    Reconcile and report

    Pull statements and as-of balances into your reporting. The ledger keeps proving its own trial balance in the background.

The API surface

20 endpoints, generated from the served contract

This table is produced from the live OpenAPI document and checked against it before every deploy. It cannot drift from what the service actually serves.

GroupMethodPathWhat it does
Accounts and balancesGET/v1/accountsList your accounts, page by page
POST/v1/accountsOpen an account for an asset type and set its floor
GET/v1/accounts/{account_id}Read one account
PATCH/v1/accounts/{account_id}Freeze an account, close it, or adjust its floor
GET/v1/accounts/{account_id}/balanceThe current balance, both posted and available
GET/v1/accounts/{account_id}/balance-as-ofThe balance at any past moment, on either clock
GET/v1/accounts/{account_id}/entriesThe statement of every entry on the account, in order and page by page
Reference dataGET/v1/asset-typesList the asset types you have defined
POST/v1/asset-typesDefine something you count, such as a currency, a credit or a stock unit, and give it a precision
PATCH/v1/asset-types/{asset_type_id}Retire an asset type created by mistake, or bring it back. Its code, kind and precision never change.
Partners and sub-tenantsGET/v1/sub-tenantsList your clients
POST/v1/sub-tenantsCreate an isolated ledger for one of your own clients
PATCH/v1/sub-tenants/{sub_tenant_id}Suspend or restore a client
GET/v1/sub-tenants/{sub_tenant_id}/keysList a client’s keys and when they were last used
POST/v1/sub-tenants/{sub_tenant_id}/keysIssue a key for a client
DELETE/v1/sub-tenants/{sub_tenant_id}/keys/{key_id}Revoke a client’s key immediately
Transactions and holdsPOST/v1/transactionsPost a balanced transaction, or place a hold
GET/v1/transactions/{transaction_id}Read one transaction and its entries
POST/v1/transactions/{transaction_id}/commitSettle a hold
POST/v1/transactions/{transaction_id}/voidRelease a hold

Explore it live: API explorer · OpenAPI document · llms.txt for software agents · API reference.

Free today. Access is provisioned personally by RODMENA.

Tell us what you keep books of and we will set up a tenant, mint your first key and walk you through the tour.