> ## 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 walks you through implementing accounting in Midaz from start to finish. It assumes you are a developer who wants enough accounting context to model a real product correctly — not a full accounting textbook. By the end you will understand how the primitives fit together and how to wire up a complete Pix payment with proper 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 is built on 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, and 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 movements are classified.

<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, annotating each posting with its classification.
</Note>

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

* **Assets** define *what* is moved — currencies (BRL, USD), points/miles, crypto tokens, or internal units of value — along with decimal precision and regulatory metadata.
* **Accounts** are balance containers. Each belongs to a portfolio, a segment, an account type, and an asset code, and is identified by an **alias** (e.g. `@external/BRL`) to make 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.

Mapping a CoA in Midaz means deciding which balances you need, classifying them with Account Types, organizing them with segments and portfolios on a ledger, and assigning `code` values on your Accounting Entries to reflect your account 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 — and let you classify accounts according to 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

For how to enable Account Type validation, the behavior of the `type` field, and how to manage Account Types via the API, see **[Account Types](/en/midaz/account-types)**.

### Understanding balance buckets

Before wiring up two-phase flows, it helps to know that each balance tracks funds in distinct buckets. A balance amount is exposed through three fields:

* **`available`** — funds free to be spent or sent right now. Debits and credits to a balance move this number.
* **`onHold`** — funds reserved by a pending `hold` and not yet committed. They are removed from `available` but still belong to the account until the hold is committed or cancelled.
* **`scale`** — the number of decimal places used to interpret the integer amounts (e.g. `scale: 2` means `available: 100` is `1.00`). It defines precision, not a separate pool of funds.

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. Rather than computing accounting classifications by hand for each movement, you register rubrics once and let Midaz resolve them automatically — recording the resulting `routeCode` and `routeDescription` on each operation.

Rubrics are configured **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` → `on_hold` on the source).                       |
| **Commit** | `commit` | Confirms a previously held amount, releasing `on_hold` to the destination.                                   |
| **Cancel** | `cancel` | Cancels a hold, returning `on_hold` 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, so every stage of an operation lands on the right ledger entry. You register these 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 are debited/credited, balance keys, validation rules — and 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 a transaction is submitted, Midaz resolves the matching Transaction Route, then resolves each Operation Route and its rubric for the action being performed. It validates that balances exist, debits do not exceed available balance, assets match, and the ledger stays balanced — before anything is recorded.

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, moving, 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 and submit the corresponding actions; each stage resolves its own rubric.

## 7. Validation modes

***

By default, if no rubric is registered for an action, the transaction proceeds normally and the `routeCode`/`routeDescription` fields are simply left empty for that operation — no error is raised. This graceful mode is convenient while you are still onboarding routes.

In production, set `accounting.validateRoutes` to `true` in the [Ledger Settings](/en/midaz/ledgers#ledger-settings) to enforce that every action has a registered rubric:

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

With strict mode enabled, any operation whose action and direction has no registered mapping is rejected with `0117 ErrAccountingRouteNotFound`. This prevents movements from silently landing without an accounting classification.

<Tip>
  Use **strict mode** (`validateRoutes: true`) in production ledgers where every transaction type must be accounted for. Keep the graceful default only while onboarding 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.
