Skip to main content
A Transaction in Midaz records a complete financial event. A transaction often uses multiple accounts and balances. Midaz runs on a double-entry accounting system that keeps every financial movement balanced. With the multiple balances feature, each operation specifies the account and the balance key to use. You can then debit or credit different logical balances of the same account (for example, credit, operational, or collateral).
If you do not provide a balanceKey, the transaction uses the default balance.

Double-entry accounting


The double-entry system follows one principle. Every transaction has two entries: a debit and a credit. This structure records all financial activity and keeps your accounts balanced. Each transaction affects two accounts and keeps them in balance:
  • Debits show the value received or the resources consumed.
  • Credits show the value given or the resources provided.
Midaz tracks and balances every debit and credit automatically.

Example

In this example, you transfer R$1000 from one account to another. The transaction has two operations:
  • One operation to debit R$1,000.00 from the source account.
  • One operation to credit R$1,000.00 to the destination account.
Midaz captures both entries automatically. You can view and analyze these movements through the API or Lerian Console.

N:N Transactions (Many-to-Many)


Traditional financial systems limit transactions to one-to-one or one-to-many relationships. Midaz supports N:N transactions. A single transaction can use multiple source and destination accounts.

Examples

  • Marketplace payout: a single escrow account pays multiple sellers, and each seller pays a platform fee.
  • Peer-to-peer with fees: one transaction debits the payer and credits both the payee and a fee account.
Midaz processes each case as a single atomic transaction. It debits and credits all parties together.

Atomicity and integrity


Transactions are atomic. Either all operations succeed, or none do. Partial financial events do not occur. If any part of a transaction fails validation — for example, one account has insufficient funds — Midaz does not apply the transaction. The ledger stays consistent.

Transaction source


A transaction in Midaz can start from a single source or from multiple sources.
The sum of the values in source must equal the value after send. It must also equal the sum of the values in distribute.

Single source

In a single-source transaction, Midaz takes the amount from one source account. You can also name a specific balance.

Example

In this example (Figure 1):
  • Midaz takes BRL 30.00 from @account1 (balance credit).
  • It sends 100% to @destinationAccount1 (balance operational)
Single-source transaction moving BRL 30.00 from one source account to a single destination account

Figure 1. Example of a single source transaction.

Code examples

Multi-source

In a multi-source transaction, Midaz draws funds from multiple accounts or balances.

Example

In this example (Figure 2):
  • Midaz sends BRL 30.00 to the destination account (@destinationAccount1).
    • BRL 15.00 from @account1 (balance default).
    • BRL 15.00 from @account2 (balance investment).
  • The destination account receives 100% of the amount.
Multi-source transaction where BRL 30.00 is drawn from two source accounts and sent to a single destination account

Figure 2. Example of a multi-source transaction.

Code examples

Transaction destination


Like sources, destinations can be single or multiple.

Single destination

In a single-destination transaction, Midaz sends the amount to only one destination account.

Example

In this example (Figure 3):
  • Midaz takes BRL 30.00 from an external account (@external/BRL).
  • It sends 100% to the destination account (@destinationAccount1).
Single-destination transaction moving BRL 30.00 from an external account to one destination account

Figure 3. Example of a single destination transaction.

Code examples

Multi-destination

In a multi-destination transaction, Midaz divides the amount among multiple destination accounts. You can distribute values by shares, fixed amounts, or the remaining balance.

Example

In this example (Figure 4):
  • Midaz takes BRL 100 from the source account (@account1).
  • 38% of the amount goes to account 2 (@account2).
  • 50% goes to account 3 (@account3).
  • A fixed BRL 2.00 goes to account 4 (@account4).
  • The remaining amount goes to account 5 (@account5).
Multi-destination transaction splitting BRL 100.00 from one source account across five destination accounts by percentage and fixed amounts

Figure 4 Example of a multi-destination transaction.

Code example

Multi-source and multi-destination


These transactions use multiple sources and multiple destinations. They are useful for cases like a crowdfunding campaign. Midaz pools the contributions and distributes them among multiple recipients.

Example

In this example (Figure 5):
  • The donation is BRL 4,000.00. Midaz takes it from four different accounts.
    • 25% comes from account 1 (@account1).
    • 25% comes from account 2 (@account2).
    • 40% comes from account 3 (@account3)
    • 10% comes from account 4 (@account4).
  • Midaz distributes the donations to four separate accounts. Each account receives a 25% share of the total.
Multi-source and multi-destination transaction drawing BRL 4,000.00 from four accounts and distributing it evenly across four destination accounts

Figure 5. Example of a multi-source and multi-destination transaction.

Code examples

Transaction statuses


Every transaction in Midaz has a status. The status reflects its current stage in the lifecycle. You need these statuses to design transaction flows, configure event consumers, and read ledger data.
Use the NOTED status to import legacy transactions, record audit trails, and log compliance events. It fits any case where the transaction must exist in the ledger but the balances settled elsewhere already.

Status transitions

Transactions follow predictable paths through these statuses:
  • Standard flow:APPROVED (single step)
  • Two-phase flow:PENDINGAPPROVED (commit) or CANCELED (cancel)
  • Reversal flow:CREATEDAPPROVED (automatic)
  • Annotation flow:NOTED (terminal, no transitions)
Once a transaction reaches NOTED or CANCELED, it cannot transition further. Both are terminal statuses.

Transaction flow


When a transaction starts, Midaz validates:
  • The accounts involved.
  • The specified balances (balanceKey, or default if not given).
  • Permissions (allowSending, allowReceiving).
  • Sufficient available funds in the selected balance.
If validation passes and the transaction is not pending (Two-Phase Transaction flow), Midaz transfers the amount immediately. It moves the amount from the source account to the destination account, from the available balance. This process is synchronous. On success, the transaction status becomes APPROVED.
Initiate this type of transaction only if you intend to commit it to the ledger immediately.
For transactions that need validation or approval first, use the pending flag to create a Two-Phase Transaction.

Two-Phase Transaction


In this flow, Midaz creates the transaction with status PENDING. Midaz does not move funds right away. Instead, it reserves the amount in the correct balance (balanceKey, or default if you do not provide one).
  • Midaz moves the reserved funds from available to on_hold.
  • Midaz records no operations (debits or credits) in the ledger yet.
  • You must explicitly commit to execute the transfer, or cancel to release the funds.
The Two-Phase Transaction feature supports Flowker. You reserve funds at the start of a workflow and run validations later. Midaz guarantees execution if the workflow approves the transaction.
In Figure 6, you can see an example of a two-phase transaction with anti-fraud.
Two-phase transaction in an anti-fraud workflow, reserving funds first and committing or cancelling them after validation

Figure 6. Anti-fraud workflow example

Two-Phase Transaction flow

1. Create a Two-Phase Transaction

Midaz validates accounts, the specified balances (balanceKey), permissions (allowSending, allowReceiving), and available funds. If valid:
  • Midaz reserves funds in the correct balance.
  • Midaz sets the transaction status to PENDING.
  • Midaz stores the metadata but posts no debit or credit yet.

2. Commit or cancel the pending transaction

  • Commit: finalizes the transaction. Funds move from on_hold to the destination balance, and Midaz records the debit and credit operations.
  • Cancel: releases the reserved funds back to available in the same balance.

Past Transactions


Midaz also supports past transactions. Institutions can import legacy financial events and keep historical accuracy.
  • Use the optional transactionDate field to set the original date of the transaction.
  • Transactions with financial impact recalculate the historical balance state as if Midaz processed them on that date.
  • Transactions created through the Create a Transaction Annotation endpoint validate structure but do not affect balances. They suit audits, compliance, and imports where balances must stay unchanged.

Example

Submit all past transactions before you start live operations. Midaz then recalculates balances consistently across the ledger.

Transactions with no financial impact


Midaz can create transactions that it records in the ledger but that do not affect account balances. These transactions keep structural integrity and leave balances unchanged. This feature is useful when you need to:
  • Import legacy transactions but keep balances unchanged.
  • Record audit or compliance events.
  • Add business operations that the ledger must track but that do not move funds.

How does it work?

When you create a transaction without financial impact:
  • Midaz stores the balance and balanceAfter fields as 0 to preserve double-entry validation.
  • Each operation has a balanceAffected (boolean) field:
    • true → the operation affects the account balance.
    • false → Midaz records the operation in the ledger but does not change balances.
Even when Midaz updates no balances, it enforces double-entry rules. This keeps consistency across all transactions in the ledger.

Example

Real-time event publishing


Midaz supports real-time event publishing through RabbitMQ. You can track the status of your transactions as they happen. After you enable it, every transaction generates an event: APPROVED, PENDING, CANCELED, CREATED, or NOTED. External systems subscribe to these events through topic-based routing. For more about how to publish and consume transaction events, see the Event publisher page.

Inflows, outflows, and external accounts


Midaz uses a double-entry ledger. All value that enters or leaves the system must pass through one special account: the External Account. Midaz represents this account as @external/{{assetCode}}. It acts as the bridge between Midaz and the external financial world (banks, PSPs, payment rails, and so on).

Why does this matter?

When you first initialize the ledger, all accounts — including @external — start with a zero balance. To reflect real-world balances, such as institutional funds held outside Midaz, you must initiate a transaction that injects funds into Midaz accounts and debits the external account. This is the only way to bring funds into Midaz.

Inflows – Adding value into the Ledger

To credit an internal account from outside the ledger:
  • Source: @external/{{assetCode}} (e.g., @external/BRL).
  • Destination: One or more internal accounts (e.g., @organization.main).
Example: First deposit into the Ledger Your institution holds R$10,000 in a real-world bank and wants to bring it into Midaz. You create a transaction: This debits the external account and credits your internal account. The external account now shows a negative balance. This is expected: it represents the total amount your organization brought into the ledger.

Outflows – Moving value out of the Ledger

To move value from the ledger to an external destination:
  • Source: One or more Midaz accounts.
  • Destination: @external/{{assetCode}}.
Example: A Pix transfer from Ledger to an external bank This debits @accountA and credits the external account. Your system then transfers the funds to the recipient through SPI or another integration.

Behavior and balance rules

  • @external/{{assetCode}} can have a zero or negative balance, but never positive.
  • Its balance is always the inverse of the combined balance of all Midaz accounts that hold that asset.
  • Every inflow increases internal liquidity and reduces the external account balance (i.e., simulates a deposit).
  • Every outflow does the reverse.
All value that moves between the outside world and the Midaz ledger must go through the external account.Nothing enters or leaves the system without a formal transaction. This gives you full traceability, balance integrity, and compliance with double-entry principles.

Setting a custom transaction date


The transactionDate field lets you set a custom date for a transaction, independent of when you submit it to the API.
  • Optional. If you omit it, Midaz uses the current timestamp.
  • Accepted formats:
    • ISO 8601 with timezone: 2026-01-15T10:30:00Z
    • ISO 8601 without timezone: 2026-01-15T10:30:00
    • Date only: 2026-01-15
  • Constraint: you cannot use a future date. A future date returns error 0121.
  • Constraint: you cannot use it on PENDING transactions. A transactionDate with "pending": true returns error 0122.

Use cases

  • Record transactions that occurred in the past (for example, same-day corrections)
  • Import historical financial data into a new ledger
  • Reconcile with external systems that use a different posting date

Transaction Routes


The Transaction Routes API enables structured, validated transaction processing in Midaz.
The Lerian Console and product documentation call this concept Accounting Routes. The API resource and endpoints keep the transactionRoute / Transaction Routes name. Both refer to the same transaction-level route.
The Transactions API runs financial events: debits and credits between accounts. Transaction Routes define templates for how to structure and validate these events. This keeps them consistent and correct. Think of it as the validation layer. It makes business transactions follow predefined patterns and keep a proper financial structure. For example, a fee, a deposit, or a payout may need different account types, validation rules, and structures. You do not handle validation separately for each transaction. Instead, you configure predefined rules. These rules tell Midaz: “When the user submits this type of transaction, validate it against these account requirements and structure patterns. Each Transaction Route combines multiple Operation Routes. An Operation Route defines one component of a transaction. It sets the account requirements, the direction (source or destination), and the validation rules for each “leg” of the financial event.
Do not use the route field in FromTo inputs — use routeId instead. routeId accepts a UUID that references an Operation Route created through the Operation Routes API. Midaz keeps the route field for backward compatibility, but it will remove the field in a future version.

Why does it matter?

With Transaction Routes, you:
  • Keep a consistent transaction structure across your application.
  • Make your ledger more maintainable, predictable, and reliable.
  • Validate financial events against predefined patterns.
  • Configure transaction templates without code changes.
  • Maintain data integrity through structured validation.

Initiating a transaction


When you create transactions through the API, always implement idempotency to prevent duplicate processing. Midaz provides built-in idempotency support through the X-Idempotency header. Validate the X-Idempotency-Replayed response header to tell new transactions from cached replays. See Retries and idempotency for details.
There are two main ways to initiate a transaction:

Using DSL

This feature is deprecated. Midaz will remove it in the next release.Update your workflows as soon as possible to prevent errors or downtime.
A Domain-Specific Language (DSL) simplifies user interaction. It focuses on specific domain concepts, so non-developers can perform complex tasks without technical skills. A DSL reduces boilerplate code and embeds constraints in its syntax. It enforces business rules and lowers the risk of errors. But its predefined patterns can limit flexibility. They make custom parsers or new requirements harder to build. The Transactions DSL in Midaz is called Gold. It simplifies transaction processing with an accounting syntax. It stores transaction information in .gold files. Business teams can then define transactions and work together with technical teams. To use the DSL, follow these steps:
1
Create the .gold file according to the Transactions DSL structure.
2
Submit the file through the Create a Transaction using DSL endpoint.
For more about the DSL structure, see the Transactions DSL page.

Using JSON endpoint

JSON endpoints provide a flexible, developer-friendly standard for data interchange. They give you precise control over request structures for custom workflows and specific use cases. They work with many programming languages, which makes integration and debugging easier. But this flexibility can add verbosity and user errors, because developers handle validation manually. For non-developers, JSON can be harder to read than a Domain-Specific Language (DSL) for everyday tasks.
If you need to reserve funds before you complete the transfer, set the pending field to true (Two-Phase Transaction flow).

Reverting a transaction


Midaz supports transaction reversal. You can undo an approved transaction. Midaz creates a mirror transaction that inverts the original debits and credits. This mechanism keeps full audit trails and cancels the financial impact on account balances.
Reversal creates a new transaction that compensates for the original. The original transaction remains in the ledger history for complete traceability.

How does it work?

When you revert a transaction, Midaz automatically:
  1. Inverts operations:
    • CREDIT operations become source operations (from).
    • DEBIT operations become destination operations (to).
  2. Creates a new transaction with:
    • Same amount and asset code.
    • Same description and metadata.
    • Inverted operations (recipients become senders, senders become recipients).
    • Initial status: CREATED (not PENDING) → then progresses to APPROVED.
    • parentTransactionID that references the original transaction.
  3. Processes the reversal through the standard transaction flow: validation, balance updates, and history recording.

Example

Consider this scenario: Original transaction:
  • Account A (debit -100) → Account B (credit +100)
Reversal transaction created:
  • Account B (debit -100) → Account A (credit +100)
Result:
  • Account A returns to its previous balance (receives back the -100).
  • Account B returns to its previous balance (loses the +100).
  • Both transactions remain in the ledger history for audit purposes.
  • The reversal transaction includes a parentTransactionID that points to the original.

Reversal restrictions

Midaz enforces strict rules to keep ledger integrity. A reversal fails in these cases:

1. Transaction already has a reversal

  • Midaz allows only one reversal per transaction.
  • This prevents multiple reversals of the same transaction.

2. Transaction is already a reversal

  • You cannot revert a transaction that is itself a reversal.
  • This prevents “reversals of reversals.”

3. Transaction status is not APPROVED

  • You can revert only approved transactions.
  • You cannot revert a transaction with status PENDING, CREATED, or CANCELED.

4. Transaction cannot be reverted

  • This happens when the transaction has no valid operations to invert.
  • For example, a transaction without standard CREDIT or DEBIT operations.
Midaz reverses the CREDIT and DEBIT operations. It does not reverse ON_HOLD or RELEASE operations.

Use cases

Transaction reversal helps in several operational scenarios:

1. Incorrect payment reversal

A customer paid BRL 500 to the wrong supplier.
  • Revert the transaction.
  • Funds return to the customer’s account.
  • The customer can start a new payment to the correct supplier.

2. Purchase cancellation

A store processed a BRL 1,000 sale, but the customer cancels the purchase.
  • Revert the sale transaction.
  • Funds return to the customer’s account.

3. Operational error correction

An operator created a transaction with the wrong amount.
  • Revert the incorrect transaction.
  • Create a new transaction with the correct amount.

4. Product return

A customer purchased and paid BRL 200, but returned the product.
  • Revert the payment transaction.
  • The customer receives a refund.

5. Integration failure compensation

A transaction is approved but fails in an external system.
  • Revert to undo the accounting operation.
  • Balances return to their previous state.

Blocking and unblocking funds


Some scenarios require you to flag funds as blocked — a compliance hold, a court order, a fraud investigation — and later release them. Midaz supports this with two dedicated endpoints. These endpoints create transactions whose operations are typed BLOCK and UNBLOCK. These transactions accept the same body as the Create a Transaction using JSON endpoint, with two key differences:
  • Always posted immediately. Midaz ignores the pending field in the request body and overrides it to false. Block and unblock transactions are never two-phase. They go straight to APPROVED.
  • Operations are typed BLOCK or UNBLOCK. This classification distinguishes them in the ledger and in operation queries. You can audit blocked-fund movements without a look at the metadata.
Midaz is agnostic about the business reason to block or unblock funds. Record the reason in the metadata field.
A Block transaction records a ledger movement with BLOCK-typed operations. This differs from the balance-level controls in Balances: permission flags (allowSending / allowReceiving) and collateral balances. Those controls restrict movement but record no transaction. Use a collateral balance for a standing operational restriction. Use a Block transaction when you need an auditable ledger entry.

Managing transactions


You can manage your Transactions through the API or Lerian Console.

Via API

Via Lerian Console

You can do all Transaction management actions — view, create, and cancel — through Lerian Console. Learn more in the Managing Transactions guide.