> ## 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 for multi-account customers

> Model multiple Midaz accounts under a single customer — with segregated balances, ledgers, statements, and external identifiers per account.

A single customer rarely has a single balance. The same person can hold a main account, a benefit account, a blocked account, a product sub-account, or a promotional balance. Each balance has its own rules, its own statement, and its own reconciliation needs.

The common shortcut treats these as labels on one account and sorts them out in application code. That works until balances, ledgers, statements, or operational rules must diverge. At that point, a single account can no longer tell the truth about where the money is.

This page shows the reference architecture for **one customer with many Midaz accounts**. It maps each part of the model to a native platform entity. Then it walks through an example: three accounts for the same customer document.

## Why this matters

***

For **product and operations teams**, each balance becomes its own account. The Ledger then enforces every segregation rule — a blocked outflow, a benefit-only spend, a promotional balance with an expiry. The rule lives in the Ledger, not in application logic. Each account carries its own statement and reconciliation trail.

For **engineering teams**, each external address resolves to a specific account before Midaz posts a transaction. Core banking numbers and payment-rail identifiers each point to one balance. You never guess which balance an incoming event belongs to. There is no separate balance store to keep in sync with the Ledger.

| One account with labels                                 | Many accounts per customer                                        |
| ------------------------------------------------------- | ----------------------------------------------------------------- |
| Balance "types" live in metadata or app code            | Each balance is its own Account with its own ledger and statement |
| Blocking or restricting funds requires custom logic     | Account Type and route rules enforce restrictions at the Ledger   |
| Statements must be filtered and reassembled per balance | Each account produces a clean, independent statement              |
| External identifiers all point to the same balance      | Each external identifier resolves to a specific account           |
| Reconciliation mixes unrelated movements                | Reconciliation is separated by account by design                  |

## The reference architecture

***

The model is **one owner, N accounts, N external identifiers**:

* **One owner** — the customer, identified by a document (CPF, CNPJ, tax ID). The owner represents *who* holds the relationship. It does not carry a balance and does not decide transaction routing.
* **N accounts** — each account is a self-contained accounting position, with its own balance, ledger, statement, and rules.
* **N external identifiers** — the addresses other systems (a core banking platform, a payment rail) use to reach a specific account. Each identifier resolves to exactly one account.

A middleware layer keeps the map between external identifiers and accounts. It resolves each identifier to the correct account *before* the call to Midaz. Midaz remains the source of truth for accounts, balances, and entries.

<Frame caption="Reference architecture: one customer, many accounts.">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/flowchart-multiaccounts.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=4bc292432ee995aeabaa2061bfee73ff" alt="One customer, many accounts — reference architecture" width="1485" height="668" data-path="images/en/d2/flowchart-multiaccounts.svg" />
</Frame>

<Note>
  When balance, ledger, statement, or operational rule differs by destination, point each identifier at a distinct account. An external identifier is **not** just a nickname for one shared balance.
</Note>

## How Midaz maps the model

***

Every part of this architecture maps to a native Midaz entity. You do not build a separate balance store or invent an accounting layer.

| Concept                        | Midaz entity                                                                                                                       | What it does                                                                                              |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| The owner (customer)           | [**Holder**](/en/midaz/crm/holders)                                                                                                | Identity behind the accounts (`NATURAL_PERSON` or `LEGAL_PERSON`), keyed by `document`. Holds no balance. |
| Each balance position          | [**Account**](/en/midaz/accounts)                                                                                                  | Source of truth for balance, entries, and statement.                                                      |
| The nature of each balance     | [**Account Type**](/en/midaz/account-types)                                                                                        | Classifies an account (main, benefit, blocked) and enables route validation.                              |
| All accounts of one customer   | [**Portfolio**](/en/midaz/portfolios)                                                                                              | Groups a customer's accounts to view the total relationship.                                              |
| External address → account     | [**Account alias**](/en/midaz/accounts#account-aliases) + [**`entityId`**](/en/midaz/accounts#entity-id-external-system-reference) | The alias is how transactions address an account; `entityId` links it to an external system's identifier. |
| Banking and regulatory context | [**Instrument (CRM)**](/en/midaz/crm/crm-getting-started)                                                                          | Attaches branch, account number, and regulatory fields. Links a Holder to a specific account.             |

<Tip>
  Much of what an external "alias registry" would do is already native. The account **alias** is the in-Ledger address. **`entityId`** stores your external system's identifier. The middleware's job is narrow — translate an external rail identifier into the right account alias, then post.
</Tip>

## Prerequisites

***

This example assumes a running Midaz environment with the following in place:

| Requirement                 | Details                                                                                |
| --------------------------- | -------------------------------------------------------------------------------------- |
| **Midaz** (v3.x.x+)         | Core Ledger with an Organization and Ledger already created                            |
| **A registered asset**      | `BRL` registered as the operating asset in the Ledger                                  |
| **Account Type validation** | Enabled per-Ledger so each account's nature is enforced (see Step 1)                   |
| **CRM** (optional)          | Part of the ledger binary — use it to attach identity, banking, and regulatory context |

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

## Building three accounts for one customer

***

The customer with document `12345678900` needs three accounts. The **main** account is free for ordinary movement. The **benefit** account follows product rules. The **blocked** account accepts inflows but restricts outflows.

<Steps>
  <Step title="Enable Account Type validation">
    Turn on validation so every account must declare a registered type. This is what lets the Ledger enforce each account's nature.

    ```json theme={null}
    PATCH /v1/organizations/{org_id}/ledgers/{ledger_id}/settings

    {
      "accounting": {
        "validateAccountType": true
      }
    }
    ```

    Settings take effect immediately — no redeployment needed.
  </Step>

  <Step title="Register the Account Types">
    Create one Account Type per balance nature. The `keyValue` is what each account's `type` field must match.

    ```json theme={null}
    POST /v1/organizations/{org_id}/ledgers/{ledger_id}/account-types

    {
      "name": "Main Account",
      "description": "Ordinary account, free for regular movement",
      "keyValue": "main_account"
    }
    ```

    Repeat for `benefit_account` (movement under product rules) and `restricted_account`. The `restricted_account` is the **blocked** account: it accepts inflows but conditions or blocks outflows.
  </Step>

  <Step title="Create the three accounts">
    Each account links to the `BRL` asset and declares its `type`. It carries an `alias` (its in-Ledger address) and an `entityId` (its identifier in your external system).

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

    {
      "name": "Main account — 12345678900",
      "assetCode": "BRL",
      "alias": "@cust_12345678900_main",
      "entityId": "0001/12345-1",
      "type": "main_account"
    }
    ```

    Create the benefit account with `alias` `@cust_12345678900_benefit`, `entityId` `0001/88888-2`, and `type` `benefit_account`. Create the blocked account with `alias` `@cust_12345678900_blocked`, `entityId` `0002/77777-0`, and `type` `restricted_account`.

    <Tip>
      The `entityId` is where you store the external address that other systems use to reach this account — your map between Midaz and your source system.
    </Tip>
  </Step>

  <Step title="Register the customer as a Holder">
    Create one Holder for the customer. The same Holder owns all three accounts and keeps identity in one place.

    <Note>
      In Midaz v4, CRM is part of the ledger binary, so it needs no separate service or port. The organization ID travels in the URL path — see [Getting started with CRM](/en/midaz/crm/crm-getting-started) for the full schema.
    </Note>

    ```bash theme={null}
    curl -X POST http://localhost:3002/v1/organizations/{org_id}/holders \
      -H "Content-Type: application/json" \
      -d '{
        "type": "NATURAL_PERSON",
        "name": "Jane Smith",
        "document": "12345678900",
        "contact": {
          "primaryEmail": "jane.smith@example.com"
        }
      }'
    ```

    Save the returned `holderId` — you'll use it in the next step.
  </Step>

  <Step title="Link each account to the Holder">
    Create one Instrument per ledger account to attach banking and regulatory context. The Instrument powers CRM-driven features and keeps customer-facing details out of the Ledger.

    ```bash theme={null}
    curl -X POST http://localhost:3002/v1/organizations/{org_id}/holders/{holder_id}/instruments \
      -H "Content-Type: application/json" \
      -d '{
        "ledgerId": "<your-ledger-id>",
        "accountId": "<main-account-id>",
        "bankingDetails": {
          "branch": "0001",
          "account": "12345",
          "type": "CACC",
          "countryCode": "BR"
        },
        "metadata": {
          "purpose": "main"
        }
      }'
    ```

    Notice how the main account's `entityId` (`0001/12345-1`) decomposes into the `branch` (`0001`) and `account` (`12345`) you record here. That external address now resolves to one specific account. Repeat for the benefit and blocked accounts, and point `accountId` at each one.
  </Step>
</Steps>

The result: one customer, three accounts, three distinct external addresses. Each account keeps its own balance, statement, and rules under a single Holder.

| Owner         | External identifier | Midaz account       | Use                     | Treatment                                      |
| ------------- | ------------------- | ------------------- | ----------------------- | ---------------------------------------------- |
| `12345678900` | `0001/12345-1`      | `@cust_..._main`    | Main account            | Free for ordinary movement                     |
| `12345678900` | `0001/88888-2`      | `@cust_..._benefit` | Benefit account         | Movement governed by product rules             |
| `12345678900` | `0002/77777-0`      | `@cust_..._blocked` | Court-ordered / blocked | Inflow allowed, outflow conditioned or blocked |

## The transaction boundary

***

When an external event arrives, the resolution happens *before* the call to Midaz. Each layer stays in its lane, and that preserves accounting clarity.

<Steps>
  <Step title="External event">
    A transaction, query, or settlement arrives with an external identifier.
  </Step>

  <Step title="Middleware resolves the identifier">
    The middleware looks up the external identifier and resolves it to the correct Midaz account alias. It also applies status validation (active, blocked, closed).
  </Step>

  <Step title="Midaz posts to the right account">
    Midaz records the entry against the resolved account and preserves balance and ledger. Statement and reconciliation stay separate by account.
  </Step>
</Steps>

| Layer                  | Responsibility                                                                                               | Should not do                                                                         |
| ---------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| **CRM / registration** | Hold the commercial and identity view of the customer, including the link between document and relationship. | Transaction routing, destination decisions, or settlement rules.                      |
| **Middleware**         | Resolve external identifiers to a Midaz account before the transaction, and apply status validation.         | Invent balances, duplicate accounting, or depend on the CRM in real time for routing. |
| **Midaz**              | Record accounts, balances, entries, ledgers, and statements as the financial source of truth.                | Know external-rail details beyond the identifiers needed for integration.             |

<Tip>
  An identifier for a blocked or closed account must fail validation **before** the call to Midaz. Routing decisions belong in the middleware. The Ledger stays the source of truth for balances and entries.
</Tip>

## What this unlocks

***

* **Real segregation** — each balance has its own ledger and statement. You cannot spend a blocked balance through the main account by accident.
* **Unambiguous routing** — every external event has a single, well-defined destination account.
* **Centralized identity** — one Holder owns many accounts. Identity and contact data live in one place while balances stay separate.
* **Native, not bolted-on** — accounts, types, aliases, and `entityId` are platform primitives, so there's no parallel balance store to reconcile against the Ledger.

## What you need to get started

***

| Requirement                 | Details                                                                             |
| --------------------------- | ----------------------------------------------------------------------------------- |
| **Midaz** (v3.x.x+)         | Organization, Ledger, and a registered asset                                        |
| **Account Type validation** | Enabled per-Ledger via the [Ledger Settings API](/en/midaz/ledgers#ledger-settings) |
| **Account Types**           | One per balance nature (main, benefit, blocked, …)                                  |
| **Accounts**                | One per balance, each with an `alias` and an `entityId`                             |
| **CRM** (optional)          | A Holder per customer plus an Instrument per ledger account                         |

## Next steps

***

<CardGroup>
  <Card title="Accounts" icon="wallet" href="/en/midaz/accounts">
    The core financial unit — aliases, `entityId`, and external accounts.
  </Card>

  <Card title="Account Types" icon="tags" href="/en/midaz/account-types">
    Classify accounts and enforce their nature with route validation.
  </Card>

  <Card title="Portfolios" icon="folder-tree" href="/en/midaz/portfolios">
    Group a customer's accounts to view the total relationship.
  </Card>

  <Card title="CRM: Holders & Instruments" icon="user" href="/en/midaz/crm/holders">
    Centralize identity and attach banking and regulatory context.
  </Card>
</CardGroup>
