Skip to main content
The Bank Transfer plugin splits configuration across two levels. You can change most business settings at runtime, with no service restart. The tenant identity and the Midaz organization scope serve different purposes. Keep them distinct. On Lerian Cloud, the tenantId JWT claim in the authenticated request context identifies your tenant, and Lerian isolates your data. The X-Organization-Id header defines the Midaz organization scope inside that tenant. Every organization-scoped transfer route requires this header, in all deployment modes. A request returns 400 if it omits the header or sends a value that is not a valid UUID. Background processes, such as the TED IN poller and reconciliation workers, do not receive request headers. With TED IN polling on, these processes use the ORGANIZATION_ID environment variable as the organization context.

Configuration levels


The Bank Transfer plugin has two configuration levels:
  • Infrastructure configuration (DevOps manages it) controls URLs, credentials, authentication settings, and timeouts. Changes need a service restart.
  • Runtime settings (managed through the Admin API) control transfer limits, fee policies, operating hours, and ledger routing. Settings in the tenant_policy namespace apply to one tenant. Settings in the runtime_config namespace apply to the whole deployment. Changes take effect with no service restart.

Business decisions you can configure


GPMs and product teams care about these settings. You manage them through the Admin API at runtime, with no deploy, except deploy-time variables such as MIDAZ_FEE_MODE, which change only at restart.

Transfer limits

Set daily and monthly amount caps per tenant with usage_limits.enabled, usage_limits.daily_limit_cents, and usage_limits.monthly_limit_cents. The plugin applies the caps to each sender account, on the amount debited from the sender (totalAmount), when it processes a TED OUT or P2P transfer. The day and the month roll over at 00:00 UTC. A transfer over a cap is refused with 422 BTF-0011.

Fee policy

The deploy-time variable MIDAZ_FEE_MODE decides who prices and charges the fee of each TED OUT, TED IN, and P2P transfer:
  • legacy: plugin-fees prices the fee from its own packages. BTF_FEE_ENABLED turns it on. With false, the default, the plugin does not call plugin-fees, and every transfer runs with fee 0.
  • native: the Fees Engine of Midaz 4.1.0 or later prices and charges the fee from the fee packages of the ledger. BTF_FEE_ENABLED does not turn this fee on or off. To stop a fee, disable its Midaz fee package with enable: false, or delete the package.
  • auto (default): native on Midaz 4.1.0 or later, and legacy on an earlier version or when the first read of the version fails.
Under auto, an upgrade of Midaz to 4.1.0 or later moves Bank Transfer to native by itself. If your fee packages still live in plugin-fees, Midaz finds no package, and new transfers carry no fee. Set MIDAZ_FEE_MODE=legacy before you upgrade Midaz, then follow Migrate Bank Transfer fees to Midaz.

Fail-open vs. fail-closed

In legacy mode, the tenant policy fees.fail_closed_default (default false) decides what a plugin-fees failure does:
  • TED OUT and P2P: when plugin-fees is unavailable, the transfer proceeds with no fee (fail-open). With true, the plugin refuses the transfer (fail-closed). A fee that plugin-fees refuses always refuses the transfer.
  • TED IN: any fee failure credits the funds with fee 0. With true, the plugin does not credit, and returns the transfer to the origin bank.

TED IN receiving

TED IN polling is off by default. DevOps turns it on for the deployment with JD_POLLING_ENABLED=true, after the JD SPB credentials are in place. When the plugin cannot find the recipient of a TED IN, the tenant policy jd_polling.auto_return_authorized (default false) decides whether it returns the funds to the origin bank or retains the message for an operator. See Receive (TED IN).

Operating hours

Each tenant has one TED OUT window: operating_hours.window (HH:MM-HH:MM, default 06:30-17:00) in operating_hours.timezone (default America/Sao_Paulo). The plugin refuses a TED OUT outside the window, on weekends, and on BACEN holidays with 422 BTF-0010. P2P ignores the window.

Ledger routing

The tenant policy routing.ledger_bindings is one JSON document that binds each Midaz organization, ledger, and transfer type to its accounting routes. A binding either names the Midaz transaction and operation routes to use, or sets mode: omit to post with no routes. There is no fallback from one binding to another. Without a binding:
  • TED OUT and P2P are refused with 503 BTF-9015. The error names the missing setting in systemplaneKey and the cause in reason.
  • A TED IN is retained with reason LEDGER_ROUTE_UNRESOLVED. The plugin processes it again on each poll cycle and credits it once the binding exists.

Infrastructure configuration


DevOps sets the deploy-time environment variables (URLs, credentials, TLS, persistence, integrations, security keys). These variables require a service restart. See the full reference in Environment variables.

Runtime configuration (Admin API)


You manage runtime settings through the Admin API under /system/:namespace/:key, with no restart. Tenant policy keys live in the tenant_policy namespace. Deployment-wide keys live in runtime_config. Configurable settings include:
  • Transfer limits (daily and monthly, per tenant)
  • Fee behavior (fees.fail_closed_default, fees.max_fee_amount_cents)
  • Recipient-not-found returns for TED IN (jd_polling.auto_return_authorized)
  • Operating hours (operating_hours.window, operating_hours.timezone)
  • Ledger routing (routing.ledger_bindings)

Systemplane-managed settings

The systemplane (Admin API) manages the settings below at runtime, not at deploy time. The plugin ignores these environment variables: if you set one, it logs the WARN systemplane-managed environment variable is set and ignored. Use the systemplane to change them.
When CORS is unconfigured, the default allowed origin is the wildcard *. Any origin can then call the API, and the plugin does not validate it at startup. For production, set explicit origins through the systemplane key cors.allowed_origins instead of the wildcard.