Skip to main content
To settle a Pix at the Banco Central, an institution has to be connected to the National Financial System infrastructure. That is expensive and slow, and not every institution does it. An institution that does not uses somebody else’s connection: it becomes an indirect participant, and a direct participant settles for it and hosts it. A tenant that hosts indirect participants is a direct participant first. Everything in Setting up the rail — the ISPB binding, the organization, the ledger, the asset, the accounts, the CRM records, the twenty accounting routes — is provisioned exactly as written there. Call that the direct-participant chain, steps 1 to 6. This page is what you add on top, and its numbering continues from there. If your deployment settles only its own customers’ Pix, skip this page.
Step 7 comes before step 9, not after: without the encryption key, every registration in step 9 fails. Steps 7 and 8 are independent of each other — the posture does not validate the key, and the key is not read by the posture.
This page is the provisioning. What a hosted participation is, how an inbound credit reaches one, how its lifecycle behaves and every refusal it can answer are in Indirect participants.

Step 7: the delivery-secret encryption key

Why this step exists. When you register an indirect participant, you supply a delivery secret. The plugin signs every notice it sends to that institution’s endpoint with it, and it is how the institution knows the notice really came from you. That secret is stored encrypted, and the key that encrypts it does not come from the database. It comes from outside. If the key is not configured, every registration that carries a secret fails. This is not an edge case — it is the whole write surface of the indirect flow.
Read the guarantee in the middle of that sentence: no secret was stored. Encryption fails before any write, so there is no half-created row with a plaintext secret to go and clean up. Fixing the key and repeating the POST is the whole recovery.
409 here means “provision it”, not “try again later”. The rail looked for the key and established that it is not there, and only an operator can put it there — so repeating the call without that change fails identically. That is why the code is a 409 and says nothing about retrying.Its sibling is 503 PIX-0123, “Indirect delivery key source unavailable”, which is what you get when the key could not be read: the custody backend refused or did not answer. There, the key is not known to be missing — the read itself did not complete — so the response names the faulting dependency and retrying is the right move. Both refuse the registration and store nothing; the pair exists so you can tell an incomplete setup from an outage.
The plugin starts without the key. There is no boot refusal: the process logs a warning at startup and comes up healthy, because nothing at startup distinguishes a deployment that will host indirect participants from one that never registers a single one — the key is read on every request, not once at boot. So the symptom arrives on the first registration, not on deploy. If you did not read the startup log, the refusal is your first notice.
Where it lives, and why it is not in the systemplane. This contrast explains where each kind of value belongs on this rail.
Do not put the encryption key in the systemplane. The systemplane is the live configuration plane, readable over the admin API, and that is the right home for everything that is not a secret. Credential material does not go there, and the rail separates the two on purpose.Do not commit it either — not in a versioned .env, not in a values.yaml, not in a compose file.
The format: exactly 64 hex characters. It is an AES-256 key — 32 bytes — hex-encoded. That is 64 hex characters, not 63 and not 65.
Generate one per deployment. Do not copy another environment’s key and do not reuse another service’s.
An absent, blank, or malformed value all produce the same 409 PIX-0107. There is no default and no degradation to storing the secret in the clear. That is deliberate: a silent default here would store customer secrets encrypted with a key everybody knows.
In single-tenant, set the deployment variable:
That placeholder is deliberately not a valid key: pasted as-is it fails closed with the refusal above rather than encrypting your customers’ secrets with a value published on a documentation page. It is read at startup, so changing it needs a process restart. That is different from the ISPB binding, which is read on every call and heals without one.
Do not type the value on a command line. It ends up in your shell history and in CI logs. Read it from a vault, or type it with read -rs, which does not echo.
How to check it landed. No route reads the key back, and that is how it should be — it is a secret. There are two signals. The startup log. With the key resolvable, the “key unavailable” warning does not appear. If it does appear, no registration carrying a secret will pass. The behavior. Register an indirect participant: the response goes from 409 PIX-0107 to 201.
Think before you use the behavioral check. A registration is permanent — there is no delete route, and the only exit is close, which keeps the row and holds the ISPB. Do not spend a throwaway registration to test the key in a production environment; use an ISPB you actually intend to operate. The startup log saves you that cost.

Step 8: declare that this tenant hosts indirect participants

plugin-br-pix-jd.indirects/enabled has to be true.
204 when accepted. It is a JSON boolean, unquoted: {"value":"true"} answers 400. The management API works with the posture off, so you can register participants before you enable — what the posture gates is the money paths. The full breakdown of what each half does is in Before you register anyone.
The read fails closed. If the systemplane does not answer, if the key does not resolve, or if the value comes back the wrong type, the plugin reads it as off — never on by accident. A money path that “went back to behaving like a direct one” with nobody having touched the key is this mechanism. Look at the systemplane.

Step 9: register an indirect participant

One call runs the whole assembly: it checks the ISPB, creates the @pi_{ispb} settlement account in Midaz, and marks the participation active.
A 201 means the participation is ready to use: registration is atomic, status is always ACTIVE, and there is nothing to poll for.
Do not write an indirect participant’s ISPB into tenancy/jd_integration_binding. That key is the identity the plugin presents to JD, so a third party’s ISPB there makes the plugin introduce itself as another institution — and nothing warns you, because 8 valid digits are accepted and the write answers 204. The key is one per direct participant, not one per indirect participant: every indirect participant you host reaches the SPI through your ISPB.
Registration is permanent. There is no DELETE on /v1/indirects, and CLOSED is terminal. An indirect participant registered by mistake in a live tenant does not come back out, and its ISPB stays held against the uniqueness rule until somebody closes it. Check the name, the ISPB, and the endpoint before you call. Rehearse on a disposable environment.
The refusals, the lifecycle actions, and how to read the registry back are in Indirect participants.

The systemplane keys of the indirects namespace

Five keys, all in plugin-br-pix-jd.indirects, and all of them always exist. The three delivery and resolution keys only take effect once enabled is true, because they tune the money paths. validate_ispb_on_jd is the exception: it gates a step of registration, which works while enabled is still false.
204 when accepted, 400 when the validator refuses. Booleans and integers both go unquoted, and a value outside the range answers 400 rather than clamping silently.
Neither of the two steps that break the indirect flow on their own lives in this namespace. Identity is the systemplane key tenancy/jd_integration_binding, and without it every payment refuses with 409 PIX-0092. The encryption key lives in a deployment variable or a secret store, and without it every registration refuses with 409 PIX-0107.