Skip to main content
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.

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.
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.

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.
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.
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.
1

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.
2

Define account types

Create an Account Type per conceptual category — e.g. CASH, SETTLEMENT, FEE_REVENUE, FEE_EXPENSE, TREASURY.
3

Create segments and portfolios

Segments separate business domains (CUSTOMER_FUNDS). Portfolios manage ownership and grouping (customer_12345_wallet).
4

Create accounts

For each logical balance, create a ledger account (customer BRL account, treasury account, provider fee expense account, merchant settlement account).

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.

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 for the decimal value model. The two-phase actions move value between available and onHold on the source balance: For the full balance model — multiple balances per account, permission flags, overdraft, and history — see 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

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.
For the full model, see Accounting Entries (Rubricas).

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.

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.
1

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
2

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:
3

Transaction

Submit a transaction against the PIX_CASH_OUT Transaction Route. Move, say, 100.00 BRL from customer_12345_brl to @external/BRL.
4

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.
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. Strict mode then validates the routes on every transaction:
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.
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.

Next steps


  • Review the Accounting overview and reference pages for full field-level detail.
  • Once your ledger produces structured postings, see Lerian Reporter to transform ledger events into reconciliation files, financial statements, and COSIF-aligned regulatory outputs.