> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Accounting walkthrough

> An end-to-end, hands-on guide to designing and implementing accounting in Midaz — from chart of accounts to a working Pix payment example.

This guide shows you how to implement accounting in Midaz from start to finish. It assumes you are a developer. You want enough accounting context to model a real product, not a full accounting textbook. By the end, you understand how the primitives fit together. You can also wire up a complete Pix payment with correct double-entry postings.

For the conceptual overview and links to each reference page, see **[Accounting](/en/midaz/accounting-in-midaz)**.

## 1. Double-entry accounting fundamentals

***

Midaz uses strict double-entry bookkeeping. The rules are simple but non-negotiable:

* Every transaction **must** have at least one debit and one credit.
* Total debits **must equal** total credits.
* Every movement impacts the ledger in a balanced way.

This guarantees no drift in balances, precise audit trails, and regulation-ready financial statements. In practice, you rarely do double-entry by hand in Midaz. You model your accounts and routing once. The engine enforces balance on every transaction.

<Note>
  Think in terms of *where value comes from* (the debit side / source) and *where it goes* (the credit side / destination). Every Midaz operation lands on one side of that equation.
</Note>

## 2. Chart of Accounts in Midaz

***

In traditional accounting, the Chart of Accounts (CoA) defines account categories (Assets, Liabilities, Equity, Income, Expenses), their hierarchy, and how to classify movements.

<Note>
  Midaz does not have a dedicated Chart of Accounts API. The CoA is not a resource you create or retrieve. It is the result of how you combine assets, accounts, segments, portfolios, and account types. The `code` field on Accounting Entries (e.g. `1.1.1.001`) is where traditional account numbering appears in practice. Each `code` annotates a posting with its classification.
</Note>

Midaz lets you mirror or adapt a CoA digitally using a small set of primitives:

* **Assets** define *what* moves — currencies (BRL, USD), points/miles, crypto tokens, or internal units of value — with decimal precision and regulatory metadata.
* **Accounts** are balance containers. Each belongs to a portfolio, a segment, an account type, and an asset code. An **alias** (e.g. `@external/BRL`) identifies each account and keeps routing intuitive.
* **Segments** categorize and isolate accounts (customer vs. internal funds, business units, multi-tenant separation).
* **Portfolios** group accounts that share a purpose or belong to the same entity.

To map a CoA in Midaz, you decide which balances you need and classify them with Account Types. You then organize them with segments and portfolios on a ledger, and assign `code` values on your Accounting Entries to match your numbering scheme.

### A recommended process

<Steps>
  <Step title="Map your financial model">
    List the balances you need: customer balances, internal accounts, reserve/settlement accounts, fee and revenue accounts. This is your CoA blueprint.
  </Step>

  <Step title="Define account types">
    Create an Account Type per conceptual category — e.g. `CASH`, `SETTLEMENT`, `FEE_REVENUE`, `FEE_EXPENSE`, `TREASURY`.
  </Step>

  <Step title="Create segments and portfolios">
    Segments separate business domains (`CUSTOMER_FUNDS`). Portfolios manage ownership and grouping (`customer_12345_wallet`).
  </Step>

  <Step title="Create accounts">
    For each logical balance, create a ledger account (customer BRL account, treasury account, provider fee expense account, merchant settlement account).
  </Step>
</Steps>

## 3. Setting up Account Types

***

Account Types are **templates** for the accounts in your ledger. They define how accounts behave: allowed operations, internal vs. external classification, and reconciliation rules. They also let you classify accounts by your financial structure.

A typical setup for a payments product:

* **CASH** → liquid customer funds
* **SETTLEMENT** → funds awaiting clearing
* **FEE\_REVENUE** → fees collected
* **FEE\_EXPENSE** → provider fees
* **TREASURY** → internal operations

To enable Account Type validation, understand the `type` field, and manage Account Types via the API, see **[Account Types](/en/midaz/account-types)**.

### Understanding balance buckets

Before you wire up two-phase flows, understand that each balance tracks funds in distinct buckets. A balance exposes two amount fields:

* **`available`** — funds you can spend or send right now. Debits and credits to a balance move this number.
* **`onHold`** — funds that a pending `hold` reserves and does not yet commit. Midaz moves them out of `available`, but they still belong to the account until you commit or cancel the hold.

Both fields carry decimal strings with exact precision (for example, `"12.50"`). There is no separate `scale` field to interpret. See [Transaction amount](/en/midaz/amount) for the decimal value model.

The two-phase actions move value between `available` and `onHold` on the source balance:

| Action     | `available`                                      | `onHold`                       |
| ---------- | ------------------------------------------------ | ------------------------------ |
| **Direct** | Debited (source) / credited (destination)        | unchanged                      |
| **Hold**   | ↓ decreased on source                            | ↑ increased on source          |
| **Commit** | credited on destination                          | ↓ released from source         |
| **Cancel** | ↑ returned to source                             | ↓ released back to `available` |
| **Revert** | restored on both sides via a counter-transaction | unchanged                      |

For the full balance model — multiple balances per account, permission flags, overdraft, and history — see **[Balances](/en/midaz/balances)**.

## 4. Defining Accounting Entries (Rubricas)

***

**Accounting Entries** (Rubricas) map a transaction action to the ledger accounts it debits and credits. You register rubrics once instead of computing accounting classifications by hand for each movement. Midaz then resolves them automatically and records the resulting `routeCode` and `routeDescription` on each operation.

You configure rubrics **per action** on each Operation Route, inside the `accountingEntries` block. Source routes require the **debit** rubric, destination routes require the **credit** rubric, and bidirectional routes require **both**.

### The five transaction-lifecycle actions

| Action     | Code     | What it does                                                                                                 |
| ---------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| **Direct** | `direct` | Immediate, single-step debit/credit between two accounts, no intermediate stages (e.g. a fee or adjustment). |
| **Hold**   | `hold`   | Reserves funds by creating a pending movement (`available` → `onHold` on the source).                        |
| **Commit** | `commit` | Confirms a previously held amount, releasing `onHold` to the destination.                                    |
| **Cancel** | `cancel` | Cancels a hold, returning `onHold` value to `available` on the source.                                       |
| **Revert** | `revert` | Reverses a completed `direct` transaction via a counter-transaction.                                         |

Each action can point to different debit/credit mappings within the same rubric. Every stage of an operation then lands on the right ledger entry. You register these mappings through the Operation Route endpoints — see [Create an Operation Route](/en/reference/midaz/create-an-operation-route).

```json theme={null}
{
  "accountingEntries": {
    "direct": {
      "debit":  { "code": "1.1.1.001", "description": "Customer cash-out" },
      "credit": { "code": "2.1.1.001", "description": "External settlement" }
    },
    "hold": {
      "debit": { "code": "1.1.2.001", "description": "Pending settlement — hold" }
    }
  }
}
```

For the full model, see **[Accounting Entries (Rubricas)](/en/midaz/accounting-entries)**.

## 5. Transaction routing

***

Routing is a two-layer system that resolves at runtime:

* **Operation Routes** define the accounting logic for each leg of a transaction: which accounts to debit or credit, balance keys, and validation rules. They carry the **Accounting Entries (rubricas)** above.
* **Transaction Routes** define the business event that triggers accounting (`PIX_CASH_OUT`, `WALLET_TRANSFER`, `BANK_SLIP_SETTLEMENT`, …) and combine Operation Routes into a balanced financial event.

When you submit a transaction, Midaz resolves the matching Transaction Route. It then resolves each Operation Route and its rubric for the current action. Before it records anything, Midaz runs four checks. It confirms that balances exist, that debits do not exceed the available balance, that assets match, and that the ledger stays balanced.

For route structure, fields, the operation-type validation matrix, and API behavior, see **[Transaction Routing](/en/midaz/transaction-routing-entities)**.

## 6. End-to-end example — a Pix payment

***

Let's tie it together with a simple Pix cash-out: a customer sends BRL out of their wallet to an external account.

<Steps>
  <Step title="Account setup">
    Create the accounts on your ledger:

    * `customer_12345_brl` — Account Type `CASH`, asset `BRL`
    * `@external/BRL` — the external settlement account for funds leaving the ledger
  </Step>

  <Step title="Rubrica registration">
    On the Operation Route for the customer leg (source), register the `direct` debit rubric. On the external leg (destination), register the `direct` credit rubric:

    ```json theme={null}
    {
      "accountingEntries": {
        "direct": {
          "debit":  { "code": "1.1.1.001", "description": "Pix cash-out — customer" },
          "credit": { "code": "2.1.1.001", "description": "Pix cash-out — external settlement" }
        }
      }
    }
    ```
  </Step>

  <Step title="Transaction">
    Submit a transaction against the `PIX_CASH_OUT` Transaction Route. Move, say, `100.00 BRL` from `customer_12345_brl` to `@external/BRL`.
  </Step>

  <Step title="Resulting operations">
    Midaz records two balanced operations:

    * **Debit** `customer_12345_brl` `100.00 BRL`, `routeCode: 1.1.1.001`
    * **Credit** `@external/BRL` `100.00 BRL`, `routeCode: 2.1.1.001`

    Both share the same `transactionId`, giving you a full trail from transaction → operation → rubric.
  </Step>
</Steps>

For a two-phase flow (hold → commit/cancel), register the `hold`, `commit`, and `cancel` rubrics on the route. Submit the corresponding actions. Each stage resolves its own rubric.

## 7. Validation modes

***

Midaz controls route validation with the `accounting.validateRoutes` setting on each ledger. The default is `false`. In this graceful mode, Midaz skips route validation. It leaves the `routeCode` and `routeDescription` fields empty on every operation and raises no error. Graceful mode is convenient while you onboard routes.

In production, set `accounting.validateRoutes` to `true` in the [Ledger Settings](/en/midaz/ledgers#ledger-settings). Strict mode then validates the routes on every transaction:

```json theme={null}
{
  "accounting": {
    "validateRoutes": true
  }
}
```

In strict mode, each operation must reference a valid operation route for its action and direction. If an operation has no route, or references a route that does not exist for the action, Midaz rejects the transaction with `0117 ErrAccountingRouteNotFound`. When the route resolves, Midaz stamps `routeCode` and `routeDescription` from its rubric. This stops movements from landing without an accounting classification.

<Tip>
  Use **strict mode** (`validateRoutes: true`) in production ledgers where every transaction type needs an accounting classification. Keep the graceful default only while you onboard routes.
</Tip>

## Next steps

***

* Review the **[Accounting](/en/midaz/accounting-in-midaz)** overview and reference pages for full field-level detail.
* Once your ledger produces structured postings, see **[Lerian Reporter](/en/reporter/what-is-reporter)** to transform ledger events into reconciliation files, financial statements, and COSIF-aligned regulatory outputs.
