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

# Midaz with Pix Transaction Routes

> Model validated, reusable Pix transfer flows with Transaction and Operation Routes, from peer-to-peer payments to fee collection.

Every Pix transaction follows a pattern: debit the sender, credit the receiver, maybe collect a fee. When that pattern lives only in application code, every team that touches Pix must re-implement the same validation logic — and every implementation is a chance for inconsistency.

Transaction Routes move that pattern into the ledger itself. You define the rules once, and Midaz enforces them on every transaction automatically. The result is fewer integration errors, a clear audit trail, and a single source of truth for how Pix money flows through your system.

This page walks through two real-world scenarios — a simple peer-to-peer transfer and a transfer with fee collection — showing how to set up routes and what your team gains from using them.

## Why this matters

***

For **product and operations teams**, Transaction Routes mean predictable, auditable Pix flows without relying on application-level enforcement. Every transaction carries a reference to the route it followed, making compliance reviews and incident investigations straightforward.

For **engineering teams**, routes eliminate repetitive validation code. Instead of checking account types and fee destinations in every Pix integration, you configure the rules once and let Midaz handle enforcement at the ledger level.

| Without Routes                                                   | With Routes                                                       |
| ---------------------------------------------------------------- | ----------------------------------------------------------------- |
| Each integration must enforce its own account rules              | Define the rules once, reuse across all Pix transactions          |
| No automatic validation — constraints live in application code   | Midaz rejects transactions that don't match the route's rules     |
| Adding fees requires changes across every Pix integration        | Add a new Operation Route, create a new Transaction Route variant |
| Hard to trace which pattern a transaction was supposed to follow | Every transaction stores its route ID — straightforward to audit  |

For a deeper look at how Transaction Routes and Operation Routes work, see [Transaction Routing](/en/midaz/transaction-routing-entities).

## Prerequisites

***

Both scenarios assume a Midaz environment with the following structure already in place:

| Entity          | Alias             | Type       | Purpose                                           |
| --------------- | ----------------- | ---------- | ------------------------------------------------- |
| Alice's account | `@alice_checking` | `checking` | Sender — Alice's main checking account            |
| Bob's account   | `@bob_checking`   | `checking` | Receiver — Bob's main checking account            |
| BRL asset       | —                 | —          | Brazilian Real, registered as the operating asset |

<Note>
  Values in Midaz are represented in the smallest unit of the currency. For BRL, `15000` means R\$ 150.00 (centavos).
</Note>

## Scenario 1: Simple Pix transfer

***

Alice sends R\$ 150.00 to Bob via Pix. The money moves from one checking account to another — no fees, no splits, just a clean peer-to-peer transfer.

### The goal

* Debit Alice's checking account by R\$ 150.00
* Credit Bob's checking account by R\$ 150.00
* Validate that both accounts are of type `checking` before processing
* Make this pattern reusable for every Pix transfer between checking accounts

### Setting up the routes

<Steps>
  <Step title="Create the source Operation Route">
    This route defines the debit side of the transfer. The `account_type` rule means any account of type `checking` is valid as a source — the route doesn't hardcode a specific sender.

    ```json theme={null}
    POST /v1/organizations/{org_id}/ledgers/{ledger_id}/operation-routes

    {
      "title": "PIX - Debit Sender",
      "description": "Debits the sender's checking account in a Pix transfer",
      "code": "PIX-SEND-SRC",
      "operationType": "source",
      "account": {
        "ruleType": "account_type",
        "validIf": ["checking"]
      },
      "metadata": {
        "payment_method": "pix",
        "direction": "outbound"
      }
    }
    ```

    Save the returned `id` — you'll need it when building the Transaction Route.
  </Step>

  <Step title="Create the destination Operation Route">
    This route defines the credit side. Same rule type: any `checking` account qualifies as a valid receiver.

    ```json theme={null}
    POST /v1/organizations/{org_id}/ledgers/{ledger_id}/operation-routes

    {
      "title": "PIX - Credit Receiver",
      "description": "Credits the receiver's checking account in a Pix transfer",
      "code": "PIX-SEND-DST",
      "operationType": "destination",
      "account": {
        "ruleType": "account_type",
        "validIf": ["checking"]
      },
      "metadata": {
        "payment_method": "pix",
        "direction": "inbound"
      }
    }
    ```
  </Step>

  <Step title="Create the Transaction Route">
    Group both Operation Routes into a single Transaction Route. This is the pattern that represents "Pix Transfer" in your system.

    ```json theme={null}
    POST /v1/organizations/{org_id}/ledgers/{ledger_id}/transaction-routes

    {
      "title": "PIX Transfer",
      "description": "Standard Pix transfer between two checking accounts",
      "operationRoutes": [
        "<pix-send-src-id>",
        "<pix-send-dst-id>"
      ],
      "metadata": {
        "payment_rail": "pix",
        "spi_message_type": "pacs.008",
        "regulation": "BCB_PIX"
      }
    }
    ```

    Replace the placeholder IDs with the actual Operation Route IDs returned in the previous steps.
  </Step>
</Steps>

### Executing a Pix transfer

With the route in place, every Pix transfer references the Transaction Route ID. Midaz validates that the accounts match the route's rules before processing.

```json theme={null}
POST /v1/organizations/{org_id}/ledgers/{ledger_id}/transactions/json

{
  "chartOfAccountsGroupName": "PIX",
  "description": "Pix transfer from Alice to Bob",
  "code": "PIX-20260306-001",
  "route": "<pix-transfer-route-id>",
  "send": {
    "asset": "BRL",
    "value": 15000,
    "source": {
      "from": [
        {
          "accountAlias": "@alice_checking",
          "amount": { "asset": "BRL", "value": 15000 },
          "description": "Pix sent to Bob",
          "route": "<pix-send-src-id>"
        }
      ]
    },
    "distribute": {
      "to": [
        {
          "accountAlias": "@bob_checking",
          "amount": { "asset": "BRL", "value": 15000 },
          "description": "Pix received from Alice",
          "route": "<pix-send-dst-id>"
        }
      ]
    }
  },
  "metadata": {
    "pix_end_to_end_id": "E123456782026030614300000000001",
    "pix_key_type": "cpf",
    "pix_key": "123.456.789-00"
  }
}
```

### What happens under the hood

<Steps>
  <Step title="Midaz receives the transaction">
    The request includes the Transaction Route ID in the `route` field. Midaz loads the route configuration.
  </Step>

  <Step title="Source validation">
    For each `from` entry, Midaz checks the account against the source Operation Route rules. Alice's account is type `checking` — matches the `account_type` rule. Validation passes.
  </Step>

  <Step title="Destination validation">
    For each `to` entry, Midaz checks the account against the destination Operation Route rules. Bob's account is type `checking` — validation passes.
  </Step>

  <Step title="Transaction is processed">
    Both validations pass, so Midaz creates the transaction atomically: debits `@alice_checking` by R\$ 150.00 and credits `@bob_checking` by R\$ 150.00.
  </Step>
</Steps>

<Tip>
  If Alice tried to send from a `savings` account instead, Midaz would reject the transaction — the route only accepts `checking` accounts as sources. No application-side validation needed.
</Tip>

## Scenario 2: Pix transfer with fee collection

***

Same flow as Scenario 1, but now the bank charges a R\$ 1.50 fee on each Pix transfer. This adds a third Operation Route for the fee destination, and Alice's total debit increases to R\$ 151.50.

### What changes

You already have the source and destination Operation Routes from Scenario 1. You need one additional Operation Route for the fee and a new Transaction Route that groups all three.

| Entity              | Alias               | Type      | Purpose                                          |
| ------------------- | ------------------- | --------- | ------------------------------------------------ |
| Fee revenue account | `@revenue_pix_fees` | `revenue` | Internal account that collects Pix transfer fees |

### Setting up the fee route

<Steps>
  <Step title="Create the fee Operation Route">
    Unlike the previous routes that use `account_type`, this one uses the `alias` rule type. That means it targets a specific account — `@revenue_pix_fees` — and no other account can be used.

    ```json theme={null}
    POST /v1/organizations/{org_id}/ledgers/{ledger_id}/operation-routes

    {
      "title": "PIX - Fee Collection",
      "description": "Credits the bank's revenue account with the Pix transfer fee",
      "code": "PIX-FEE-DST",
      "operationType": "destination",
      "account": {
        "ruleType": "alias",
        "validIf": "@revenue_pix_fees"
      },
      "metadata": {
        "fee_type": "pix_transfer_fee"
      }
    }
    ```
  </Step>

  <Step title="Create the Transaction Route with fee">
    This route groups the original source and destination routes with the new fee route. It's a separate Transaction Route from the simple transfer — your system can offer both variants.

    ```json theme={null}
    POST /v1/organizations/{org_id}/ledgers/{ledger_id}/transaction-routes

    {
      "title": "PIX Transfer with Fee",
      "description": "Pix transfer between checking accounts with fee collection",
      "operationRoutes": [
        "<pix-send-src-id>",
        "<pix-send-dst-id>",
        "<pix-fee-dst-id>"
      ],
      "metadata": {
        "payment_rail": "pix",
        "includes_fee": true
      }
    }
    ```
  </Step>
</Steps>

### Executing a Pix transfer with fee

Alice sends R\$ 150.00 to Bob. The bank collects R\$ 1.50. Alice's total debit is R\$ 151.50.

```json theme={null}
POST /v1/organizations/{org_id}/ledgers/{ledger_id}/transactions/json

{
  "chartOfAccountsGroupName": "PIX",
  "description": "Pix transfer from Alice to Bob (with fee)",
  "code": "PIX-20260306-002",
  "route": "<pix-transfer-with-fee-route-id>",
  "send": {
    "asset": "BRL",
    "value": 15150,
    "source": {
      "from": [
        {
          "accountAlias": "@alice_checking",
          "amount": { "asset": "BRL", "value": 15150 },
          "description": "Pix sent to Bob + transfer fee",
          "route": "<pix-send-src-id>"
        }
      ]
    },
    "distribute": {
      "to": [
        {
          "accountAlias": "@bob_checking",
          "amount": { "asset": "BRL", "value": 15000 },
          "description": "Pix received from Alice",
          "route": "<pix-send-dst-id>"
        },
        {
          "accountAlias": "@revenue_pix_fees",
          "amount": { "asset": "BRL", "value": 150 },
          "description": "Pix transfer fee",
          "route": "<pix-fee-dst-id>"
        }
      ]
    }
  },
  "metadata": {
    "pix_end_to_end_id": "E123456782026030614300000000002",
    "fee_amount": 150
  }
}
```

**Result:** Alice is debited R\$ 151.50. Bob receives R\$ 150.00. The bank collects R\$ 1.50 in fees. All in a single atomic transaction — fully balanced, fully auditable.

### What this unlocks

* **Transparent fee collection** — the fee is a first-class ledger entry, not hidden metadata. Finance and compliance teams see exactly where the R\$ 1.50 went.
* **Reusable building blocks** — the source and destination Operation Routes are shared between the simple and fee variants. You only add what changes.
* **Route-level control** — your system can offer both "PIX Transfer" and "PIX Transfer with Fee" as distinct products, each backed by its own Transaction Route.
* **Easy evolution** — need a percentage-based fee? A split across multiple revenue accounts? Add new Operation Routes and compose a new Transaction Route. Existing flows remain untouched.

## Understanding rule types

***

The two rule types serve different purposes. Choosing the right one depends on whether the account in a route should be dynamic or fixed.

| Rule type      | `validIf` format                                                         | Behavior                                                    | When to use                                                                                   |
| -------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `account_type` | **Array of strings** — e.g., `["checking"]` or `["checking", "savings"]` | Accepts any account that matches one of the specified types | Dynamic participants — the sender or receiver can be any account of that type                 |
| `alias`        | **String** — e.g., `"@revenue_pix_fees"`                                 | Must target a specific account by its alias                 | Fixed participants — the route always hits the same account, like a fee or settlement account |

<Tip>
  You can combine both rule types within a single Transaction Route. Scenario 2 does exactly that: `account_type` for the dynamic sender and receiver, `alias` for the fixed fee account.
</Tip>

## What you need to get started

***

| Requirement                 | Details                                                                                                                                              |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Midaz** (v3.x.x+)         | Core ledger with Transaction Route validation enabled                                                                                                |
| **Route validation config** | Enable route validation via the Ledger Settings API: `PATCH /v1/organizations/{org_id}/ledgers/{ledger_id}/settings` with `{"validateRoutes": true}` |
| **Accounts and asset**      | At minimum: two customer accounts and a BRL asset registered in the ledger                                                                           |
| **Operation Routes**        | One per operation leg (source, destination, fee)                                                                                                     |
| **Transaction Route**       | Groups the Operation Routes into a reusable pattern                                                                                                  |

<Note>
  Transaction Route validation must be explicitly enabled per ledger. See [Working with Transaction Routing](/en/midaz/transaction-routing-entities#working-with-transaction-routing) for the configuration steps.
</Note>

## Next steps

***

<CardGroup>
  <Card title="Transaction Routing" icon="route" href="/en/midaz/transaction-routing-entities">
    Understand how Operation Routes and Transaction Routes work at a deeper level.
  </Card>

  <Card title="Transactions" icon="arrow-right-arrow-left" href="/en/midaz/transactions">
    Learn about Midaz's double-entry transaction model and N:N capabilities.
  </Card>

  <Card title="Pix with automated fees" icon="calculator" href="/en/midaz/midaz-for-pix-with-fees">
    Combine the Pix Plugin with the Fees Engine for automated fee management.
  </Card>

  <Card title="Pix Switch" icon="money-bill-transfer" href="/en/midaz/plugins/pix/pix-switch">
    Explore the full Pix Plugin architecture and connection models.
  </Card>
</CardGroup>
