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

# Environment variables

> Configure the Pix Direct via JD rail: JD OAuth and JDPI endpoints, dynamic QR code hosting with JWS, Midaz ledger binding, and notification settings.

Pix Direct, via JD connects your ledger straight to the Pix arrangement through JD's DICT and SPI gateway. DevOps sets its behavior through environment variables at deploy time. To change a variable, restart the service. This page covers the variables **distinctive to this rail**. For the datastore, multi-tenancy, streaming, telemetry, and authentication knobs that every Lerian Go service shares, see [BYOC configuration essentials](/en/reference/byoc-configuration).

<Note>
  These variables describe a **single-tenant deployment**. On the managed multi-tenant offering (SaaS), the client-specific values here — JD credentials, the Midaz ledger binding, the CRM connection, the public QR host — are resolved automatically per tenant by the platform, never from a deployment's environment.
</Note>

<Note>
  In the tables below, the **Default / Required** column shows the default value. A bold qualifier (for example **Required**) marks variables you must set. `—` means no default. `🔒` marks a **secret**. Inject it at deploy time from your secret store, and never commit it. This page lists variable names and behavior only. It prints no secret values.
</Note>

## Server and port

The service listens on the address in `SERVER_ADDRESS` (default `:8080`). The liveness, readiness, and version probes bind this same port. See [Server](/en/reference/byoc-configuration#server) for the shared server knobs and [Default network ports](/en/reference/default-network-ports).

## JD integration

Credentials and endpoints for JD's OAuth-secured API and its Pix (JDPI) surface.

| Variable                   | Default / Required   | Description                                              |
| -------------------------- | -------------------- | -------------------------------------------------------- |
| `JD_BASE_URL`              | **Required**         | Base URL of the JD API.                                  |
| `JD_CLIENT_ID`             | **Required**         | OAuth client ID for the JD API.                          |
| `JD_SECRET`                | 🔒 **Required**      | OAuth client secret for the JD API.                      |
| `JD_GRANT_TYPE`            | `client_credentials` | OAuth grant type used against JD.                        |
| `JD_USE_SERVICE_SEGMENTS`  | `false`              | Route calls through JD service segments when `true`.     |
| `JDPI_MAX_RETRIES`         | `2`                  | Retry attempts on a failed JDPI call.                    |
| `JDPI_RETRY_BASE_DELAY_MS` | `100`                | Base backoff delay in milliseconds between JDPI retries. |

<Warning>
  **Your own ISPB is not an environment variable.** It comes from the systemplane key `tenancy/jd_integration_binding`, field `ispb`, and there is no environment fallback.

  While that key is empty, the rail starts, answers its health probe, and refuses **every** payment on **every** money route with `409 PIX-0092`. One end-to-end battery collected 86 refusals from that single unprovisioned value. Writing the key heals a running deployment on its next request, with no restart. The step-by-step is in [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup).
</Warning>

## Dynamic QR code hosting

The rail hosts signed (JWS) dynamic-QR payloads and the JWK set used to verify them, and serves those documents under the host in `QRCODE_PUBLIC_BASE_URL`. The public route shapes, the scheme-less host form, and BACEN's 77-character payload-URL budget these paths spend are the contract of the [QR codes reference section](/en/reference/interfaces/pix-jd/create-dynamic-qr-code); the variables below set the pieces this deployment controls.

| Variable                   | Default / Required         | Description                                                                          |
| -------------------------- | -------------------------- | ------------------------------------------------------------------------------------ |
| `QRCODE_PUBLIC_BASE_URL`   | **Required**               | Scheme-less host (FQDN) where the plugin serves dynamic-QR payloads and the JWK set. |
| `QRCODE_PAYLOAD_PATH`      | `v1/qrcodes/payload`       | Path segment where the plugin exposes signed QR payloads.                            |
| `QRCODE_JWK_PATH`          | `v1/qrcodes/jwks`          | Path segment where the plugin exposes the JWK set.                                   |
| `QRCODE_JWS_CONTENT_TYPE`  | `application/jose`         | `Content-Type` returned for the signed payload.                                      |
| `QRCODE_JWKS_CONTENT_TYPE` | `application/jwk-set+json` | `Content-Type` returned for the JWK set.                                             |

## Midaz ledger binding

Which Midaz organization, ledger, asset, and external account this rail books Pix movements against, plus the ledger service endpoints and machine-to-machine credentials.

| Variable                | Default / Required           | Description                                                                          |
| ----------------------- | ---------------------------- | ------------------------------------------------------------------------------------ |
| `MIDAZ_ORGANIZATION_ID` | **Required**                 | Midaz organization UUID that owns the Pix ledger.                                    |
| `MIDAZ_LEDGER_ID`       | **Required**                 | Midaz ledger UUID for Pix bookings.                                                  |
| `MIDAZ_ASSET_ID`        | **Required** (single-tenant) | Asset **code** booked for Pix operations, for example `BRL`. No default.             |
| `MIDAZ_EXTERNAL_ID`     | **Required** (single-tenant) | **Alias** of the external clearing account, for example `@external/BRL`. No default. |
| `MIDAZ_URL_ONBOARDING`  | **Required**                 | Midaz onboarding service URL.                                                        |
| `MIDAZ_URL_TRANSACTION` | **Required**                 | Midaz transaction service URL.                                                       |
| `MIDAZ_CLIENT_ID`       | —                            | OAuth client ID for Midaz M2M.                                                       |
| `MIDAZ_CLIENT_SECRET`   | 🔒 —                         | OAuth client secret for Midaz M2M.                                                   |
| `MIDAZ_TIMEOUT`         | `30000`                      | Midaz request timeout in milliseconds.                                               |

<Note>
  There is no separate Access Manager address for Midaz. The rail mints its outbound Midaz token against the same Access Manager it validates inbound bearers with, `PLUGIN_AUTH_HOST`. See [BYOC configuration essentials](/en/reference/byoc-configuration).
</Note>

<Warning>
  `MIDAZ_ASSET_ID` and `MIDAZ_EXTERNAL_ID` carry **no default**, and both names lie about their shape: the first wants an asset code (`BRL`) and the second an account alias (`@external/BRL`), despite the `_ID`. A UUID in either one answers `PIX-4011` without naming an account, and leaving either unset refuses every posting with `409 PIX-0106`, naming both halves.

  The systemplane keys `tenant_policy/midaz.asset_id` and `tenant_policy/midaz.external_id` accept a write and answer `204`, but nothing reads them — the two variables above are the only source. See [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup).
</Warning>

## Accounting routes

The rail books each Pix flow onto a pair of Midaz operation routes — one credit leg, one debit leg, across ten profiles. **Those twenty route identifiers are not environment variables.** They live in the systemplane keys `tenant_policy/routing.<profile>.operation_credit_route` and `tenant_policy/routing.<profile>.operation_debit_route`, with no environment fallback.

<Warning>
  The `TRANSACTION_ROUTE_*` and `OPERATION_ROUTE_*` variables were removed. A leftover value earns one startup warning and is never loaded. A missing route leg refuses its own money path with `409 PIX-0105` while every other flow keeps working, so a single flow that "does not work" points here first.
</Warning>

The profiles, the exact key names, and how to write them are in [Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup).

## Jobs and limits

| Variable                                                   | Default / Required | Description                                                        |
| ---------------------------------------------------------- | ------------------ | ------------------------------------------------------------------ |
| `JOBS_CRON`                                                | `*/10 * * * * *`   | Cron expression for the reconciliation/housekeeping job.           |
| `JOBS_CRON_TRANSACTIONS`                                   | `*/10 * * * * *`   | Cron expression for the transaction-processing job.                |
| `JOBS_RECONCILE_STUCK_THRESHOLD_SEC`                       | `80`               | Age in seconds after which a pending cash-out is flagged as stuck. |
| `MAX_PAGINATION_LIMIT` · `MAX_PAGINATION_MONTH_DATE_RANGE` | `100` · `3`        | Upper bounds on list page size and date-range span.                |

<Note>
  The daily window transaction limits are accounted in is **not** an environment variable. It lives in the systemplane keys `tenant_policy/transaction_limits.daily_period_init` and `tenant_policy/transaction_limits.daily_period_end`, in both deployment modes; both take a clock hour from 0 to 23. The retired `TRANSACTION_LIMIT_DAILY_PERIOD_INIT` and `TRANSACTION_LIMIT_DAILY_PERIOD_END` variables are ignored.
</Note>

## Notifications

Optional end-customer notifications for Pix events. Leave the provider blocks unset to disable that channel.

| Variable                 | Default / Required | Description                                     |
| ------------------------ | ------------------ | ----------------------------------------------- |
| `SENDGRID_API_KEY`       | 🔒 —               | SendGrid API key for email notifications.       |
| `SENDGRID_FROM_EMAIL`    | —                  | Sender address for email notifications.         |
| `SENDGRID_FROM_TEMPLATE` | —                  | SendGrid template ID used for the message body. |
| `TWILIO_ACCOUNT_SID`     | 🔒 —               | Twilio account SID for SMS notifications.       |
| `TWILIO_AUTH_TOKEN`      | 🔒 —               | Twilio auth token for SMS notifications.        |
| `TWILIO_PHONE_NUMBER`    | —                  | Sender phone number for SMS notifications.      |

## CRM

| Variable            | Default / Required | Description                               |
| ------------------- | ------------------ | ----------------------------------------- |
| `CRM_URL`           | —                  | CRM service URL for counterparty lookups. |
| `CRM_CLIENT_ID`     | —                  | OAuth client ID for CRM M2M.              |
| `CRM_CLIENT_SECRET` | 🔒 —               | OAuth client secret for CRM M2M.          |

## Indirect participants

Only relevant if this deployment settles Pix on behalf of other institutions.

| Variable                            | Default / Required                            | Description                                                                                                                                                   |
| ----------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INDIRECTS_DELIVERY_ENCRYPTION_KEY` | 🔒 **Required** to host indirect participants | AES-256 key that encrypts each indirect participant's delivery secret at rest. Exactly 64 hex characters (32 bytes), from `openssl rand -hex 32`. No default. |

<Warning>
  Without this key, **every** indirect-participant registration is refused with `409 PIX-0107` — and refused before any write, so no plaintext secret is ever stored. An absent, blank, or malformed value all produce the same refusal: there is no default and no degradation to storing the secret in the clear. The `409` means "provision it", not "try again": its retryable sibling is `503 PIX-0123`, which is what a key that could not be **read** answers.

  The rail starts without it. Startup logs a warning and the process comes up healthy, so the symptom arrives on the first registration, not on deploy. Read at startup, so a change needs a restart.

  See [Hosting indirect participants](/en/interfaces/pix-jd/hosting-indirect-participants) for the onboarding this key unlocks.
</Warning>

## Runtime configuration (systemplane)

This rail mounts the systemplane admin API on its main port, gated by `SYSTEMPLANE_ENABLED`.

| Variable              | Default / Required | Description                                             |
| --------------------- | ------------------ | ------------------------------------------------------- |
| `SYSTEMPLANE_ENABLED` | `false`            | Enable the systemplane runtime-configuration admin API. |

When enabled, the service exposes an authenticated plane for reading and writing runtime configuration. See [Systemplane](/en/reference/platform/systemplane/overview) for the API, namespaces, and required permissions.

Several values this rail needs are **only** reachable through that plane, in both deployment modes, and a deployment that leaves them unset starts healthy and refuses money:

| Systemplane key                                                  | What it carries                                         | Unset                                                    |
| ---------------------------------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------- |
| `tenancy/jd_integration_binding`                                 | your own ISPB, in the `ispb` field of a JSON **string** | `409 PIX-0092` on every money route                      |
| `tenant_policy/routing.<profile>.operation_{credit,debit}_route` | the twenty accounting route legs                        | `409 PIX-0105` on the flows that use the missing profile |
| `tenant_policy/transaction_limits.daily_period_{init,end}`       | the daily limit window                                  | limit accounting has no window                           |
| `plugin-br-pix-jd.indirects/enabled`                             | whether this tenant hosts indirect participants         | indirect resolution stays off                            |

<Note>
  With `SYSTEMPLANE_ENABLED=false` the `/system` route group is not mounted at all, so every configuration write answers `404`, and a money path that cannot read its configuration answers the retryable `503 PIX-0051` rather than a provisioning refusal. The write-side permission is `systemplane:write`; without it the writes answer `403`.
</Note>

[Setting up the rail](/en/interfaces/pix-jd/pix-jd-setup) walks every one of these keys, with the exact body each write takes and how to confirm it landed.

## Health and readiness

The rail exposes `GET /health` (liveness) and `GET /readyz` (readiness) on the main port, plus `/metrics` and `/version`. See [Health and readiness](/en/reference/health-and-readiness) for the response shape and startup/drain behavior.
