---
title: codespar_ledger
description: Double-entry ledger. Record money movement, read balances, create accounts, and read the signed agentic receipt of a spend. Routes to the tenant's self-hosted Lerian Midaz; the books, not the money.
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tabs, Tab } from "fumadocs-ui/components/tabs";

<MetaToolHeader tool="codespar_ledger" />

The system of record. [`codespar_pay`](/docs/concepts/meta-tools/pay) and [`codespar_charge`](/docs/concepts/meta-tools/charge) move real money through PSPs; the ledger records what happened, immutably and auditably, on the tenant's own [Lerian Midaz](https://github.com/LerianStudio/midaz) instance.

## Actions

<MetaToolActions tool="codespar_ledger" />

## Example

`action: "entry"`, the default: a journal entry moving R$ 150,00 from a wallet account to a revenue account. Amounts are in minor units, with a per-asset `scale`.

<Split min={380}>
<SplitPane label="Call · tools/call">

```json title="arguments"
{
  "name": "codespar_ledger",
  "arguments": {
    "action": "entry",
    "asset": "BRL",
    "scale": 2,
    "source": [{ "account": "@wallet/consumer_0000", "amount": 15000 }],
    "destination": [{ "account": "@revenue/store_0000", "amount": 15000 }],
    "description": "Example order settled"
  }
}
```

</SplitPane>
<SplitPane label="Result">

Result shape: see runtime. The tool document says `receipt` returns the Control Record (mandate → quote → payment → delivery, with a tamper-evident chain hash and any settle-time exceptions) and names no field for any action. The published document is [`/v1/meta-tools.json`](https://api.codespar.dev/v1/meta-tools.json).

</SplitPane>
</Split>

## When to use

- **Recording a settlement** in your own books after a charge or payout: `entry`, with `source` debits equal to `destination` credits.
- **Reading a balance or opening an account**: `balance` by account UUID; `account` with an alias such as `@wallet/consumer_0000`, a display name and a Midaz `type`.
- **Answering "what did this agent actually settle, and under which mandate"**: `receipt` by `receipt_id`, or `receipts` for a consumer, newest first. These read the signed receipt store, not the journal, and every receipt read is itself audited.

The ledger is asset-agnostic: no currency or country routing, and multi-asset (`BRL`, `USD`, `USDC`, ...) with a `scale` per asset.

## Arguments

| Field | Type | Required | Description |
|---|---|---|---|
| `action` | `string` | No | `entry` (default) \| `balance` \| `account` \| `receipt` \| `receipts` |
| `source` | `array` | For `entry` | Debit side(s): `[{ account (alias), amount (minor units) }]` |
| `destination` | `array` | For `entry` | Credit side(s), same shape. Debits must equal credits |
| `asset` | `string` | For `entry`, `account` | Asset or currency code: `BRL`, `USD`, `USDC`, ... |
| `scale` | `number` | No | Decimal places for the asset. Default 2; JPY is 0, most crypto 6 or 8 |
| `description` | `string` | No | Transaction description (`entry` only) |
| `account` | `string` | For `balance` | Account UUID to read balances for |
| `alias` | `string` | For `account` | Account alias, e.g. `@wallet/user_123` |
| `name` | `string` | For `account` | Account display name |
| `type` | `string` | No | Midaz account type: `deposit` (default), `savings`, `external` |
| `receipt_id` | `string` | For `receipt` | The agentic receipt id (`rcpt_...`) |
| `consumer_id` | `string` | No | Whose receipts to list (`receipts`). Defaults to the session user |
| `limit` | `number` | No | Max receipts to list (`receipts`), default 50 |
| `metadata` | `object` | No | Free-form metadata stored on the entry or account |

## Errors and what to do

| Error | Cause | What to do |
|---|---|---|
| `invalid_args` | An `entry` whose debits do not equal its credits, a `balance` without `account`, an `account` without `alias`, an unknown `action`. Nothing is posted. | Fix the call against the Arguments table. |
| `no_eligible_providers` | The tenant's Midaz instance is not connected on this project. | Connect it once in `/dashboard/auth-configs` (see Notes). |
| A receipt not found | `receipt_id` is not a receipt of this consumer's organization. | Check the id from the payment result; receipts are scoped to the caller's organization. |

## Money and mandate

No money moves on this tool: an `entry` is a record, and a wrong entry is corrected by a reversing entry, never by editing. `receipt` and `receipts` are how an operator or auditor reads back the mandate a spend ran under; the receipt is the Control Record described under [audit chain](/docs/concepts/audit-chain), signed and chain-hashed.

## Related

- [`codespar_pay`](/docs/concepts/meta-tools/pay) and [`codespar_charge`](/docs/concepts/meta-tools/charge): the money the ledger records
- [`codespar_wallet`](/docs/concepts/meta-tools/wallet): the governed balance, whose settlement receipt this tool reads
- [Audit chain](/docs/concepts/audit-chain): the Control Record and its chain hash
- [Agent with a Wallet cookbook](/docs/cookbooks/agent-with-wallet): wallet balances backed by a ledger

## Notes

**Operator setup.** The ledger is the tenant's own Midaz instance. The operator connects it once in `/dashboard/auth-configs`; credentials are stored in the vault. See [Lerian Midaz](https://github.com/LerianStudio/midaz) for self-hosting.

**From the SDK.** `session.ledger(args)` is the typed wrapper; `session.execute("codespar_ledger", arguments)` takes the same arguments as the MCP call.
