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

# Transactions

> Record financial events with Midaz double-entry Transactions — multiple Balances, debits, credits, and full traceability across Accounts.

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

<Note>
  If you do not provide a `balanceKey`, the transaction uses the **default balance**.
</Note>

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

<Danger>
  The sum of the values in `source` must equal the value after `send`. It must also equal the sum of the values in `distribute`.
</Danger>

### 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`)

<Frame caption="Figure 1. Example of a single source transaction.">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/single-source.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=8867866e614ebd29f2abc801b03ad894" alt="Single-source transaction moving BRL 30.00 from one source account to a single destination account" width="932" height="384" data-path="images/en/d2/single-source.svg" />
</Frame>

**Code examples**

<CodeGroup>
  ```json JSON Example expandable theme={null}
  {
    "description": "single source transaction",
    "send": {
      "asset": "BRL",
      "value": "30.00",
      "source": {
        "from": [
          {
            "account": "@account1",
            "balanceKey": "credit", // optional
            "amount": {
              "asset": "BRL",
              "value": "30.00"
            }
          }
        ]
      },
      "distribute": {
        "to": [
          {
            "account": "@destinationAccount1",
            "balanceKey": "operational", // optional
            "share": {
              "percentage": 100
            }
          }
        ]
      }
    }
  }
  ```

  ```go DSL Example theme={null}
  (transaction v1  
    (description "single source transaction")  
    (send BRL 3000
      (source
        (from @account1 credit :amount BRL 3000)		
      )
      (distribute
        (to @destinationAccount1 operational :share 100)
      )	
    )
  )
  ```
</CodeGroup>

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

<Frame caption="Figure 2. Example of a multi-source transaction.">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/multi-source.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=a662de8e32affc1346da13432daabcd8" alt="Multi-source transaction where BRL 30.00 is drawn from two source accounts and sent to a single destination account" width="1116" height="526" data-path="images/en/d2/multi-source.svg" />
</Frame>

**Code examples**

<CodeGroup>
  ```json JSON Example theme={null}
  {
    "description": "multi-source transaction",
    "send": {
      "asset": "BRL",
      "value": "30.00",
      "source": {
        "from": [
          {
            "account": "@account1",
            "balanceKey": "default",
            "amount": {
              "asset": "BRL",
              "value": "15.00"
            }
          },
          {
            "account": "@account2",
            "balanceKey": "investment",
            "amount": {
              "asset": "BRL",
              "value": "15.00"
            }
          }
        ]
      },
      "distribute": {
        "to": [
          {
            "account": "@destinationAccount1",
            "share": {
              "percentage": 100
            }
          }
        ]
      }
    }
  }
  ```

  ```go DSL Example theme={null}
  (transaction v1
    (description "multi-source transaction")
    (send BRL 3000 
      (source
        (from @account1 credit :amount BRL 1500)
        (from @account2 investment :amount BRL 1500)
      )
      (distribute
        (to @destinationAccount1 :share 100)
      )
    )
  )
  ```
</CodeGroup>

## 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`).

<Frame caption="Figure 3. Example of a single destination transaction.">
  <img src="https://mintcdn.com/lerian-49cb71fc/Cb_meREQqa6luqbJ/images/en/d2/single-destination.svg?fit=max&auto=format&n=Cb_meREQqa6luqbJ&q=85&s=c027a71eaa987cc22a90171bbb326cc2" alt="Single-destination transaction moving BRL 30.00 from an external account to one destination account" width="960" height="384" data-path="images/en/d2/single-destination.svg" />
</Frame>

**Code examples**

<CodeGroup>
  ```json JSON Example theme={null}
  {
     "description":"single destination transaction",
     "send":{
        "asset":"BRL",
        "value":"3000",
        "source":{
           "from":[
              {
                 "account":"@external/BRL",
                 "amount":{
                    "asset":"BRL",
                    "value":"3000"
                 }
              }
           ]
        },
        "distribute":{
           "to":[
              {
                 "account":"@destinationAccount1",
                 "share":{
                    "percentage":100
                 }
              }
           ]
        }
     }
  }
  ```

  ```go DSL Example theme={null}
  (transaction v1
    (description "single destination transaction")  
    (send BRL 3000
      (source
        (from @external/BRL :amount BRL 3000)		
      )
      (distribute
        (to @destinationAccount1 :share 100)
      )	
    )
  )
  ```
</CodeGroup>

### 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`).

<Frame caption="Figure 4 Example of a multi-destination transaction.">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/multi-destination.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=fc0a0dff5a1a99b2ffda26988f3fed47" alt="Multi-destination transaction splitting BRL 100.00 from one source account across five destination accounts by percentage and fixed amounts" width="1077" height="856" data-path="images/en/d2/multi-destination.svg" />
</Frame>

**Code example**

<CodeGroup>
  ```json JSON Example theme={null}
  {
     "description":"multi-destination transaction",
     "send":{
        "asset":"BRL",
        "value":"10000",
        "source":{
           "from":[
              {
                 "account":"@account1",
                 "amount":{
                    "asset":"BRL",
                    "value":"10000"
                 }
              }
           ]
        },
        "distribute":{
           "to":[
              {
                 "account":"@account2",
                 "share":{
                    "percentage":38
                 }
              },
              {
                 "account":"@account3",
                 "share":{
                    "percentage":50
                 }
              },
              {
                 "account":"@account4",
                 "amount":{
                    "asset":"BRL",
                    "value":"200"
                 }
              },
              {
                 "account":"@account5",
                 "remaining":"remaining"
              }
           ]
        }
     }
  }
  ```

  ```go DSL Example theme={null}
  (transaction v1  
    (description "multi-destination transaction")  
    (send BRL 10000
      (source
        (from @account1 :amount BRL 10000)		
      )
      (distribute
        (to @account2 :share 38)  
        (to @account3 :share 50)  
        (to @account4 :amount BRL 200)  
        (to @account5 :remaining)  
      )	
    )
  )
  ```
</CodeGroup>

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

<Frame caption="Figure 5. Example of a multi-source and multi-destination transaction.">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/multi-source-destination.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=bc6796fc6414907407362317958eb382" alt="Multi-source and multi-destination transaction drawing BRL 4,000.00 from four accounts and distributing it evenly across four destination accounts" width="1047" height="820" data-path="images/en/d2/multi-source-destination.svg" />
</Frame>

**Code examples**

<CodeGroup>
  ```json JSON Example theme={null}
  {
     "description":"multi-source and multi-destination transaction",
     "send":{
        "asset":"BRL",
        "value":"4000.00",
        "source":{
           "from":[
              {
                 "account":"@account1",
                 "share":{
                    "percentage":25
                 }
              },
              {
                 "account":"@account2",
                 "share":{
                    "percentage":25
                 }
              },
              {
                 "account":"@account3",
                 "share":{
                    "percentage":40
                 }
              },
              {
                 "account":"@account4",
                 "share":{
                    "percentage":10
                 }
              }
           ]
        },
        "distribute":{
           "to":[
              {
                 "account":"@donation1",
                 "share":{
                    "percentage":25
                 }
              },
              {
                 "account":"@donation2",
                 "share":{
                    "percentage":25
                 }
              },
              {
                 "account":"@donation3",
                 "share":{
                    "percentage":25
                 }
              },
              {
                 "account":"@donation4",
                 "share":{
                    "percentage":25
                 }
              }
           ]
        }
     }
  }
  ```

  ```go DSL Example theme={null}
  (transaction v1 
    (description "multi-source and multi-destination transaction")  
    (send BRL 400000|2  
      (source  
        (from @account1 :share 25)		  
        (from @account2 :share 25)  
        (from @account3 :share 40)  
        (from @account4 :share 10)  
      )
      (distribute  
        (to @donation1 :share 25)  
        (to @donation2 :share 25)  
        (to @donation3 :share 25)  
        (to @donation4 :share 25)  
      )
    )
  )
  ```
</CodeGroup>

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

| Status     | What it means                                                                                                                                                    | Affects balances? | How it's created                                                                                                   |
| :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------- | :----------------------------------------------------------------------------------------------------------------- |
| `CREATED`  | A reversal transaction was initiated and is being processed. This is a transient status that automatically progresses to `APPROVED` once the reversal completes. | Yes               | [Revert a Transaction](/en/reference/midaz/revert-a-transaction)                                                   |
| `APPROVED` | The transaction completed successfully. Funds have been moved between accounts.                                                                                  | Yes               | Direct transaction (no `pending` flag), commit of a `PENDING` transaction, or automatic progression from `CREATED` |
| `PENDING`  | A two-phase transaction is awaiting confirmation. Funds are reserved in `on_hold` but not yet transferred.                                                       | Yes (reservation) | [Create a Transaction](/en/reference/midaz/create-a-transaction-using-json) with `"pending": true`                 |
| `CANCELED` | A two-phase transaction was canceled. Reserved funds are released back to `available`.                                                                           | Yes (release)     | [Cancel a Pending Transaction](/en/reference/midaz/cancel-a-pending-transaction)                                   |
| `NOTED`    | An annotation transaction recorded in the ledger without affecting balances. Operations preserve the double-entry structure but all balance fields are zeroed.   | No                | [Create a Transaction Annotation](/en/reference/midaz/create-a-transaction-annotation)                             |

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

### Status transitions

Transactions follow predictable paths through these statuses:

* **Standard flow:** → `APPROVED` (single step)
* **Two-phase flow:** → `PENDING` → `APPROVED` (commit) or `CANCELED` (cancel)
* **Reversal flow:** → `CREATED` → `APPROVED` (automatic)
* **Annotation flow:** → `NOTED` (terminal, no transitions)

<Note>
  Once a transaction reaches `NOTED` or `CANCELED`, it cannot transition further. Both are terminal statuses.
</Note>

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

<Danger>
  Initiate this type of transaction **only** if you intend to commit it to the ledger immediately.
</Danger>

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.

<Tip>
  The Two-Phase Transaction feature supports [Flowker](/en/flowker/what-is-flowker). You reserve funds at the start of a workflow and run validations later. Midaz guarantees execution if the workflow approves the transaction.
</Tip>

In *Figure 6*, you can see an example of a two-phase transaction with anti-fraud.

<Frame caption="Figure 6. Anti-fraud workflow example">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/two-phase-transaction.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=511f60dcfea8ced03f2cb86828afee7f" alt="Two-phase transaction in an anti-fraud workflow, reserving funds first and committing or cancelling them after validation" width="849" height="1445" data-path="images/en/d2/two-phase-transaction.svg" />
</Frame>

### Two-Phase Transaction flow

#### 1. Create a Two-Phase Transaction

* Use the [Create a Transaction using JSON](/en/reference/midaz/create-a-transaction-using-json) endpoint with `"pending": true`.

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.
  * Use the [Commit a Pending Transaction](/en/reference/midaz/commit-a-pending-transaction) endpoint.
  * Status: `APPROVED`.
* **Cancel**: releases the reserved funds back to `available` in the same balance.
  * Use the [Cancel a Pending Transaction](/en/reference/midaz/cancel-a-pending-transaction) endpoint.
  * Status: `CANCELED`.

## 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](/en/reference/midaz/create-a-transaction-annotation) endpoint validate structure but do **not** affect balances. They suit audits, compliance, and imports where balances must stay unchanged.

### Example

<CodeGroup>
  ```json theme={null}
  {
    "description": "past transaction example",
    "transactionDate": "2025-01-01T13:38:31.064Z", // optional
    "send": {
      "asset": "BRL",
      "value": "1000",
      "source": {
        "from": [
          {
            "accountAlias": "@external/BRL",
            "amount": {
              "asset": "BRL",
              "value": "1000"
            }
          }
        ]
      },
      "distribute": {
        "to": [
          {
            "accountAlias": "@account1_BRL",
            "amount": {
              "asset": "BRL",
              "value": "1000"
            }
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

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

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

<Danger>
  Even when Midaz updates no balances, it enforces double-entry rules. This keeps consistency across all transactions in the ledger.
</Danger>

#### Example

<CodeGroup>
  ```json theme={null}
  {
    "description": "annotation example",
    "transactionDate": "2025-01-01T13:38:31.064Z",
    "send": {
      "asset": "BRL",
      "value": "1000",
      "source": {
        "from": [
          {
            "accountAlias": "@external/BRL",
            "amount": {
              "asset": "BRL",
              "value": "1000"
            },
            "balanceAffected": false
          }
        ]
      },
      "distribute": {
        "to": [
          {
            "accountAlias": "@account1_BRL",
            "amount": {
              "asset": "BRL",
              "value": "1000"
            },
            "balanceAffected": false
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

#### Related endpoint

* [Create a Transaction Annotation](/en/reference/midaz/create-a-transaction-annotation)  — Record a transaction without financial impact in the ledger.

## 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](/en/midaz/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:

| Source        | Destination | Amount     |
| :------------ | :---------- | :--------- |
| @external/BRL | @accountA   | BRL 10,000 |

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

| Source    | Destination   | Amount    |
| :-------- | :------------ | :-------- |
| @accountA | @external/BRL | BRL 1,000 |

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.

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

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

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

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.

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

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

***

<Warning>
  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](/en/reference/retries-idempotency) for details.
</Warning>

There are two main ways to initiate a transaction:

### Using DSL

<Warning>
  This feature is deprecated. Midaz will remove it in the next release.

  **Update your workflows as soon as possible to prevent errors or downtime.**
</Warning>

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:

<Steps>
  <Step>
    Create the `.gold` file according to the [Transactions DSL](/en/midaz/transactions-dsl) structure.
  </Step>

  <Step>
    Submit the file through the [Create a Transaction using DSL](/en/reference/midaz/create-a-transaction-using-dsl) endpoint.
  </Step>
</Steps>

<Tip>
  For more about the DSL structure, see the [Transactions DSL](/en/midaz/transactions-dsl) page.
</Tip>

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

* To create a transaction with JSON, use the [Create a Transaction using JSON](/en/reference/midaz/create-a-transaction-using-json) endpoint.

<Danger>
  If you need to reserve funds **before** you complete the transfer, set the `pending` field to `true` (Two-Phase Transaction flow).
</Danger>

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

<Note>
  Reversal creates a **new transaction** that compensates for the original. The original transaction remains in the ledger history for complete traceability.
</Note>

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

<Danger>
  Midaz reverses the CREDIT and DEBIT operations. It does not reverse ON\_HOLD or RELEASE operations.
</Danger>

### 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](/en/reference/midaz/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.

<Note>
  A Block transaction records a **ledger movement** with `BLOCK`-typed operations. This differs from the balance-level controls in [Balances](/en/midaz/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.
</Note>

* Use the [Create a Block Transaction](/en/reference/midaz/create-a-block-transaction) endpoint to block funds.
* Use the [Create an Unblock Transaction](/en/reference/midaz/create-an-unblock-transaction) endpoint to release previously blocked funds.

## Managing transactions

***

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

### Via API

* [Create a Transaction using DSL](/en/reference/midaz/create-a-transaction-using-dsl) **(deprecated)** — Submit a transaction file using the Midaz DSL.
* [Create a Transaction using JSON](/en/reference/midaz/create-a-transaction-using-json) — Submit a transaction directly using a JSON payload.
* [Commit a pending transaction](/en/reference/midaz/commit-a-pending-transaction) — Finalize a reserved transaction.
* [Cancel a pending transaction](/en/reference/midaz/cancel-a-pending-transaction) — Release reserved funds without executing.
* [Revert a Transaction](/en/reference/midaz/revert-a-transaction) — Create a reversal transaction to undo an approved transaction.
* [Create an Inflow Transaction](/en/reference/midaz/create-an-inflow-transaction) — Register incoming funds from external sources into the Ledger.
* [Create an Outflow Transaction](/en/reference/midaz/create-an-outflow-transaction) — Move funds from internal accounts to the external world.
* [Create a Block Transaction](/en/reference/midaz/create-a-block-transaction) — Flag funds as blocked with `BLOCK`-typed operations.
* [Create an Unblock Transaction](/en/reference/midaz/create-an-unblock-transaction) — Release previously blocked funds with `UNBLOCK`-typed operations.
* [List Transactions](/en/reference/midaz/list-transactions) — View all Transactions in your workspace.
* [Retrieve a Transaction](/en/reference/midaz/retrieve-a-transaction) — Get details of a specific Transaction.
* [Update a Transaction](/en/reference/midaz/update-a-transaction) — Edit the metadata of an existing Transaction.
* [Create a Transaction Annotation](/en/reference/midaz/create-a-transaction-annotation) — Record a transaction without financial impact in the ledger.

### Via Lerian Console

You can do all Transaction management actions — view, create, and cancel — through Lerian Console.

Learn more in the [Managing Transactions](/en/midaz/console/managing-transactions) guide.
