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

# Multi-organization and ledgers

> Run several direct participants and several books on one Pix Direct via JD deployment: what the organization catalog is, why an economic group needs it, how to activate it as a feature toggle, and how money routes once it is on.

A fresh deployment of this rail posts every Pix movement into **one** Midaz organization and **one** ledger — the pair its binding names. Since version 2.0.2 that is the default, not the ceiling: one deployment can serve an **economic group** — a holding that operates, say, a payment institution, a credit fintech, and a bank — with each regulated institution keeping its own organization and each organization keeping as many ledgers as it needs.

The whole feature is a toggle. It lives in a single systemplane key, and while that key is empty the rail behaves byte for byte as it did before the key existed. Nothing on this page is required reading for a deployment that is one institution with one book — stop at [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup) and you are done.

## One roof, several cabinets, several drawers

***

Think of the deployment as a back office with a wall of filing cabinets. Each **cabinet** belongs to one regulated institution: its files never mix with another institution's, because a regulator audits each institution on its own. Inside a cabinet, **drawers** separate lines of business — one for the wallet product, one for the credit product. On the wall hangs an **index card** saying which cabinets and drawers exist. A clerk files money movements only into a drawer the index names; a movement addressed to a drawer that is not on the index is handed back, never filed somewhere "close enough".

The rail's vocabulary maps one to one:

| In the analogy  | On the rail                  | What it is                                                                                                                                            |
| --------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| the back office | the tenant                   | one deployment, one economic group. It holds the database and the Midaz connection for everyone under the roof                                        |
| a cabinet       | a Midaz **organization**     | exactly one direct participant — one ISPB, the 8-digit identity the Banco Central accredits. One organization is one regulated institution, never two |
| a drawer        | a **ledger**                 | one book of that institution. An organization holds one or many — for example one per product, or one per wallet family                               |
| the index card  | the **organization catalog** | the systemplane key `tenant_policy/organizations`. It declares every *additional* participant and book this tenant posts for                          |

Two consequences fall straight out of the model:

* **Every posting carries its scope.** Each transaction is written into the organization and ledger it resolved to, so each institution's records are complete on their own — regulatory and accounting reports come out per institution without untangling a shared book.
* **The rail never guesses a scope.** A movement whose organization and ledger cannot be proved against the catalog is refused before any posting. Booking money into the wrong institution's ledger is the one mistake this design exists to make impossible.

## The toggle: an empty key means off

***

The catalog key starts empty, and empty is the **not provisioned** sentinel: the tenant posts only into the organization and ledger its binding names, exactly as before the key existed. Writing a catalog turns the feature on; the pair the binding names remains the **default** — the scope every flow posts in unless it resolves another one.

<Note>
  The default organization and ledger are **never** in the catalog. Their accounting routes stay in the `routing.*` keys and their asset and clearing account in their own configuration, exactly as [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup) provisions them. The catalog declares only what the binding does not: repeating the default ledger there would give one book two sources of truth, so the rail refuses a catalog that redeclares it.
</Note>

**Deployment mode decides how far the toggle reaches.** A single-tenant deployment is one direct participant, so its catalog can add **ledgers** of its own organization — additional books, same institution. An entry carrying any other ISPB is refused at read time, because a single-tenant deployment holds one JD credential and cannot authenticate as a second institution. Acting as **several participants** — several ISPBs under one roof — is the multi-tenant shape, where the tenant is the group and each additional participant is provisioned with a JD credential of its own.

## Activate it, step by step

***

<Steps>
  <Step title="Complete the ordinary setup first">
    The catalog extends a working deployment; it does not replace the setup. Run [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup) end to end: the binding you write there makes your institution the **default** participant and its ledger the default book. If your deployment is one institution with one book, stop there — with the catalog key empty, nothing on this page changes anything.
  </Step>

  <Step title="Provision the additional book in Midaz and the CRM">
    Each additional ledger is provisioned with the same recipe the setup page walks, pointed at the new book instead of the default one:

    1. **The organization and the ledger.** An additional ledger of your own institution goes under your existing organization. An additional *participant* (multi-tenant) gets an organization of its own, because one Midaz organization is exactly one regulated institution.
    2. **The asset and the accounts** on the new ledger, including its own external clearing account — an alias such as `@external/BRL` is unique within a ledger, so each book needs its own.
    3. **The operation routes** on the new ledger, one credit-and-debit pair per money profile the book serves. Unlike the default ledger, these UUIDs do not go into the `routing.*` keys — they go inside the catalog document in the next step.
    4. **The holder records and aliases in the CRM**, addressed with the `X-Organization-Id` of the organization that owns the book. The alias's `ledgerId` is what tells the rail which book an account banks in, so on an organization with more than one ledger every alias must name its ledger.
  </Step>

  <Step title="Write the catalog">
    The catalog is written once, to `PUT /system/tenant_policy/organizations`, with the same wrapping the binding uses: the body is `{"value": ...}` and `value` is a **string** whose content is a JSON document — a list with one entry per cataloged **organization**, each naming its participant's ISPB, its Midaz organization, and that organization's ledgers with their routes. Your own organization appears here when it carries additional ledgers — never re-declaring the default ledger — and an additional participant's organization always does.

    This is the document, unwrapped, with placeholder identifiers:

    ```json theme={null}
    [
      {
        "ispb": "12345678",
        "organizationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "ledgers": [
          {
            "ledgerId": "9c858901-8a57-4791-81fe-4a34d4dd8ab5",
            "externalAlias": "@external/BRL",
            "asset": "BRL",
            "routes": {
              "in":       { "operationDebitRoute": "1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a01", "operationCreditRoute": "1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a02" },
              "inQrCode": { "operationDebitRoute": "1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a03", "operationCreditRoute": "1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a04" },
              "out":      { "operationDebitRoute": "1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a05", "operationCreditRoute": "1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a06" }
            }
          }
        ]
      }
    ]
    ```

    On a **single-tenant** deployment the entry carries your own ISPB and your own organization id, and the ledgers are the additional books; the identifiers differ per participant only in multi-tenant.

    `routes` takes up to ten profiles — `in`, `inQrCode`, `out`, `outReversal`, `intraPsp`, `intraPspReversal`, `medDebit`, `medCredit`, `pixautomaticoDebit`, `pixautomaticoReversal` — each a pair of Midaz operation route UUIDs. Only `in` and `inQrCode` are mandatory: every catalog ledger exists to receive, so a book that can serve neither inbound leg is a provisioning mistake, not a narrower book. The other eight are optional; a flow that needs an absent one refuses with `409 PIX-0105`, naming the profile, the organization, and the ledger — the same behavior an unset `routing.*` key produces on the default book.

    Let `jq` do the string escaping, as with the binding:

    ```bash theme={null}
    # CATALOG_DOCUMENT holds the JSON document above, with your own identifiers.
    CATALOG_DOCUMENT='[{"ispb":"12345678","organizationId":"...","ledgers":[...]}]'

    curl -s -o /dev/null -w '%{http_code}\n' -X PUT \
      -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
      -d "$(jq -nc --arg document "$CATALOG_DOCUMENT" '{value:$document}')" \
      "$PIX_JD_BASE_URL/system/tenant_policy/organizations"
    ```

    A successful write answers `204`. Read the key back the way you read the binding back — the value returns as a quoted string carrying your document:

    ```bash theme={null}
    curl -s -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" \
      "$PIX_JD_BASE_URL/system/tenant_policy/organizations" | jq
    ```

    The key is hot-reloadable: write it with the app running and it takes effect on the running deployment, with no restart and no redeploy.
  </Step>

  <Step title="Know what the validators refuse, and when">
    The catalog is validated twice, and the split matters: the write validator catches everything that can be judged from the document alone, so a malformed catalog is refused at the admin surface instead of discovered on a payment.

    **Refused at write time**, with `400 validation_error`:

    * a `value` that is not a string, or anything after the first JSON document;
    * an unknown field at any depth — a mistyped route-profile name included, so a typo cannot pass as a silently absent profile;
    * an `ispb` that is not exactly 8 digits; an `organizationId`, `ledgerId`, or route leg that is not a non-zero UUID;
    * an empty `externalAlias` or `asset`; a route pair missing either leg; an organization declaring no ledger;
    * a missing `in` or `inQrCode` profile on any ledger;
    * a duplicated `ispb`, `organizationId`, or `ledgerId` anywhere in the document. A `403` is a missing permission, never a rejected value.

    **Refused at read time**, because only the running rail knows your binding and mode. These surface on the money path, before any posting:

    | The rail answers | When                                                                                                                                                                                                                                                                                                                                               |
    | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `500 PIX-0125`   | the catalog contradicts the binding — it redeclares the default ledger, puts your own ISPB under another organization, gives another participant your organization, or names a foreign ISPB on a single-tenant deployment — or the stored document no longer parses. Only an operator can clear it, so the payment is refused rather than misfiled |
    | `503 PIX-0122`   | the catalog could not be **read**. Nothing is known to be wrong with it, so the refusal is retryable and clears on its own                                                                                                                                                                                                                         |
    | `500 PIX-0120`   | the catalog is fine and this movement resolved to a scope it does not declare — including an account record that names no usable ledger on an organization that has several                                                                                                                                                                        |
  </Step>

  <Step title="Understand how money routes once it is on">
    * **Every transaction is recorded in its scope.** The posting carries the organization and ledger it resolved to, so each institution's book stays complete and auditable on its own.
    * **An inbound credit finds its own book.** The receiver ISPB picks the organization; the account's CRM record picks the ledger. An organization with a single ledger tolerates a record that names none — there is nothing to choose between; one with several does not, and refuses with `500 PIX-0120` rather than guess.
    * **An outbound order names the paying participant when the tenant is several.** `POST /v1/transactions` takes an optional `payerIspb`. A tenant acting as one participant omits it and behaves exactly as before; a tenant acting as several must supply it — omitted is `422 PIX-0127`, and an ISPB the tenant does not act as is `422 PIX-0128` — because picking a payer arbitrarily would debit another institution's customer.
    * **Between two ledgers of the same organization, the transfer is internal.** An alias is unique within a ledger, so it cannot be one posting: the rail reserves the amount on the payer's ledger against its clearing account, posts the final credit on the payee's ledger against *its* clearing account, then commits the reserve. Both legs book on each ledger's own `intraPsp` route pair, and each book stays internally double-entry.
    * **Between two organizations of the same tenant, the payment is ordinary Pix.** Two organizations are two regulated participants, so the money travels the settlement rail (SPI) exactly as a payment to any other institution would — same tenant is never "same book".
    * **Each additional participant authenticates as itself.** Orders that leave an additional organization are sent to JD under that participant's own credential, provisioned per ISPB. A participant whose credential is not provisioned refuses its first order with `409 PIX-0092` and releases the hold, and the readiness probe reports it down naming that ISPB before traffic reaches it.
  </Step>
</Steps>

## Turning it off

***

Writing an empty string back to `tenant_policy/organizations` is accepted and returns the tenant to default-only behavior — the same state as before activation. It does not undo anything already booked: money posted in an additional scope stays in that ledger, and it is no longer reachable through this rail — any flow that resolves to a scope the catalog no longer declares refuses with `500 PIX-0120` before touching the ledger. So empty the key only when nothing routes to the additional books anymore: no accounts whose records point at them, no in-flight payments, and no hosted participant mounted on an additional organization. To retire one book while keeping the feature, remove that ledger's entry and leave the rest of the catalog in place — the same read-time proof applies, scope by scope.

## Where to go next

***

<Columns cols={2}>
  <Card title="Setting up the rail" href="/en/interfaces/pix-jd/pix-jd-setup">
    The provisioning chain this page extends: the ledger objects, the CRM records, the routing keys, and the binding that names the default pair.
  </Card>

  <Card title="The direct and indirect model" href="/en/interfaces/pix-jd/direct-and-indirect-model">
    How this axis differs from hosting indirect participants: an indirect is a position inside your book; an additional organization is a direct participant with books of its own.
  </Card>

  <Card title="Environment variables" href="/en/interfaces/pix-jd/pix-jd-environment-variables">
    The deploy-time configuration, and which values live in systemplane keys instead.
  </Card>

  <Card title="Pix JD error list" href="/en/reference/interfaces/pix-jd/pix-jd-error-list">
    Every `PIX-NNNN` code this page names, with its status and the `detail` text the response carries.
  </Card>
</Columns>
