Skip to main content
A fresh deployment of this rail posts every Pix movement into one Midaz organization and one ledger: the pair that its binding names. That pair is the default, not the limit. One deployment can serve an economic group. For example, a holding can operate a payment institution, a credit fintech, and a bank. Each regulated institution keeps its own organization, and each organization keeps as many ledgers as it needs. The whole feature is a toggle in a single systemplane key. While that key is empty, the rail behaves exactly as it did before the key existed. A deployment that is one institution with one book does not need this page. For that deployment, Setting up the rail is enough.

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 the files of another institution, because a regulator audits each institution separately. 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 that lists the cabinets and drawers. A clerk files money movements only into a drawer on the index. The clerk hands back a movement for a drawer that is not on the index, and never files it in a “close enough” drawer. The rail’s vocabulary maps one to one: Two results come from the model:
  • Every posting carries its scope. The rail writes each transaction into the organization and ledger that it resolved to. Each institution’s records are therefore complete on their own. Regulatory and accounting reports come out per institution, with no shared book to separate.
  • The rail never guesses a scope. It checks a movement’s organization and ledger against the catalog. If it cannot prove them, it refuses the movement before any posting. The design exists to make one mistake impossible: money in the ledger of the wrong institution.

The toggle: an empty key means off


The catalog key starts empty, and empty means not provisioned. The tenant then posts only into the organization and ledger that its binding names, as before the key existed. A catalog write turns the feature on. The pair that the binding names stays the default: the scope of every flow that does not resolve another one.
The default organization and ledger are never in the catalog. Their accounting routes stay in the routing.* keys, and their asset and clearing account stay in the midaz.* keys. Setting up the rail shows how to provision them. The catalog declares only what the binding does not. A copy of the default ledger in the catalog would give one book two sources of truth, so the rail refuses that catalog.
The deployment sets how far the toggle reaches. A self-hosted deployment is one direct participant. Its catalog can add ledgers of its own organization: more books of the same institution. An entry carrying any other ISPB is refused at read time, because a self-hosted deployment holds one JD credential and cannot authenticate as a second institution. To act as several participants, with several ISPBs under one roof, talk to Lerian about Lerian Cloud, where each additional participant gets a JD credential of its own.

Activate it, step by step


1

Complete the ordinary setup first

The catalog extends a working deployment. It does not replace the setup. Run Setting up the rail from start to end. The binding that 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. While the catalog key is empty, nothing on this page changes anything.
2

Provision the additional book in Midaz and the CRM

Provision each additional ledger with the same steps as the setup page, on the new book:
  1. The organization and the ledger. An additional ledger of your own institution goes under your existing organization. An additional participant gets its own organization, because each Midaz organization holds exactly one regulated institution.
  2. The asset and the accounts on the new ledger, with 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 for each money profile of the book. 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, with the X-Organization-Id of the organization that owns the book. The alias’s ledgerId tells the rail which book an account banks in. On an organization with more than one ledger, every alias must name its ledger.
3

Write the catalog

Write the catalog with one call to PUT /system/tenant_policy/organizations. The wrapper is the same as for the binding. The body is {"value": ...}, and value is a string whose content is a JSON document. The document is a list with one entry per catalog organization. Each entry names its participant’s ISPB, its Midaz organization, and that organization’s ledgers with their routes.Your own organization is in the catalog only when it has additional ledgers, and never with the default ledger. An additional participant’s organization is always in it.This is the document, unwrapped, with placeholder identifiers:
On a self-hosted deployment, the entry has your own ISPB and your own organization id, and the ledgers are the additional books.routes takes up to eleven profiles: in, inQrCode, out, outReversal, intraPsp, intraPspReversal, medDebit, medCredit, pixautomaticoDebit, pixautomaticoReversal, and refundSent. Each profile is a pair of Midaz operation route UUIDs.Only in and inQrCode are mandatory, because every catalog ledger exists to receive. A book that cannot serve either inbound leg shows a provisioning mistake. The other nine are optional. Without refundSent, a devolução that you send posts on out. Any other flow that needs an absent profile refuses with 409 PIX-0105, and the response names the profile, the organization, and the ledger. An unset routing.* key on the default book behaves the same way.Two fields are optional:
  • transactionRoute, inside a profile: the UUID of the Midaz transaction route that this ledger’s postings of the profile name. Set it when the ledger validates routes. Without it, such a ledger refuses the posting. Without the field, the posting carries no transaction route.
  • sharedIspbGate, on an entry: true declares that this participant shares its ISPB with another core. Its on-us transfers then ask the Courier ownership map first. The default organization declares the same fact with the key tenant_policy/onus.shared_ispb_gate_enabled. See Courier ownership map.
Let jq do the string escaping, as with the binding:
A successful write answers 204. Read the key back as you read the binding back. The value comes back as a quoted string with your document:
The key reloads without a restart. Write it while the app runs, and the running deployment uses it, with no restart and no redeploy.
4

Know what the validators refuse, and when

The rail checks the catalog two times, and the split matters. The write validator catches every error that the document alone shows. The admin surface therefore refuses a malformed catalog before any payment finds it.The write refuses these values, with 400 validation_error:
  • a value other than a string, or anything after the first JSON document.
  • an unknown field at any depth. A mistyped route-profile name is an unknown field too, so a typo cannot pass as an absent profile.
  • an ispb that is not exactly 8 digits.
  • an organizationId, ledgerId, route leg, or transactionRoute that is not a non-zero UUID.
  • an empty externalAlias or asset, a route pair without one of its legs, or an organization without a ledger.
  • a ledger without the in or the inQrCode profile.
  • the same ispb, organizationId, or ledgerId two times anywhere in the document.
A 403 means a missing permission, never a refused value.The read refuses other cases, because only the running rail knows your binding and mode. The refusals come on the money path, before any posting:
5

Understand how money routes once it is on

  • Every transaction goes into its scope. The posting carries the organization and ledger that it resolved to. Each institution’s book therefore 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 accepts a record that names no ledger, because it has no choice to make. An organization with several ledgers refuses that record with 500 PIX-0120 and does not guess.
  • An outbound order names the paying participant when the tenant is several. POST /v1/transactions takes an optional payerIspb. A tenant that acts as one participant omits it. A tenant that acts as several must send it. Without it, the order answers 422 PIX-0127. An ISPB that the tenant does not act as answers 422 PIX-0128. An arbitrary payer could debit the customer of another institution.
  • Between two ledgers of the same organization, the transfer is internal. An alias is unique within a ledger, so one posting cannot hold both legs. The rail reserves the amount on the payer’s ledger against its clearing account. It then posts the credit on the payee’s ledger against that ledger’s clearing account. Last, it commits the reserve. Both legs use each ledger’s own intraPsp route pair, and each book stays double-entry on its own.
  • Between two organizations of the same tenant, the payment is ordinary Pix. Two organizations mean two regulated participants. The money therefore goes over the settlement rail (SPI), as a payment to any other institution does. The same tenant is never “the 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.

Turning it off


You can write an empty string back to tenant_policy/organizations. The tenant then goes back to the default-only behavior, as before activation. This does not undo anything already booked. Money posted in an additional scope stays in that ledger, and this rail can no longer reach it. A flow that resolves to a scope that the catalog no longer declares refuses with 500 PIX-0120 before it touches the ledger. So empty the key only when nothing routes to the additional books. That means no accounts whose records point at them, no payments in flight, and no hosted participant on an additional organization. To retire one book and keep the feature, remove that ledger’s entry and keep the rest of the catalog. The same read-time proof applies, scope by scope.

Where to go next


Setting up the rail

The provisioning chain that this page extends: the ledger objects, the CRM records, the routing keys, and the binding that names the default pair.

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

Environment variables

The deploy-time configuration, and the values that live in systemplane keys instead.

Pix JD error list

Every PIX-NNNN code that this page names, with its status and the detail text of the response.