These are deploy-time variables set by DevOps; changes require a service restart. Runtime and business settings live in Configuration.
In the tables below, the Default / Required column shows the default value; a bold qualifier (e.g. Required, Required in production, Required if enabled) marks variables that must be set. — means no default.
Infrastructure configuration
This section is for DevOps teams. These variables are set at deployment time and require a service restart to take effect.
Application
| Variable | Default / Required | Description |
|---|
ENV_NAME | development | Environment (development, staging, production) |
DEPLOYMENT_MODE | byoc | Deployment flavor. byoc = Bring Your Own Cloud (single-tenant, operator-managed). Toggles internal SaaS vs. BYOC behaviors. |
SERVER_ADDRESS | :8080 | HTTP server address and port |
HTTP_BODY_LIMIT_BYTES | 1048576 | Maximum HTTP request body size in bytes |
ALLOW_PRIVATE_UPSTREAMS | false | ⚠️ Allow outbound adapters (CRM, Fees, JD, Midaz) to resolve to RFC1918/loopback IPs. Default false is fail-closed: production blocks DNS pivoting into private space. Enable in dev or in-cluster BYOC where upstreams legitimately live on private IPs. Cloud metadata endpoints stay blocked regardless of this flag. |
TLS
| Variable | Default / Required | Description |
|---|
SERVER_TLS_CERT_FILE | — | Path to TLS certificate file. Must be set together with SERVER_TLS_KEY_FILE. |
SERVER_TLS_KEY_FILE | — | Path to TLS private key file. Must be set together with SERVER_TLS_CERT_FILE. |
TLS_TERMINATED_UPSTREAM | false | Set to true when TLS is terminated by a load balancer or reverse proxy. |
Used when the service runs behind a load balancer or reverse proxy. Required to extract the real client IP for rate limiting and audit logs.
| Variable | Default / Required | Description |
|---|
SERVER_PROXY_HEADER | — | HTTP header carrying the real client IP (e.g. X-Forwarded-For, X-Real-IP). Empty disables proxy header parsing. |
SERVER_TRUSTED_PROXIES | Required if proxy header set | Comma-separated list of trusted proxy IPs/CIDRs. Required when SERVER_PROXY_HEADER is set to prevent IP spoofing. |
Authentication
This plugin delegates authorization to plugin-auth. Configure the connection with the variables below.
| Variable | Default / Required | Description |
|---|
PLUGIN_AUTH_ENABLED | false | Enable authorization via plugin-auth. Set to true in production. |
PLUGIN_AUTH_ADDRESS | Required if enabled | URL of the plugin-auth service. Must use HTTPS in production. |
When PLUGIN_AUTH_ENABLED=true, PLUGIN_AUTH_ADDRESS must use HTTPS in production environments. HTTP addresses are rejected at startup.
Test admin (non-production only)
BTF_TEST_ADMIN_ENABLED must remain false in production. It exposes test-only admin endpoints (e.g. POST /admin/test/circuit-breakers/reset) that are tenant-less and bypass production authentication. Enabled only by docker-compose mock-lane for E2E tests; any deployment with this flag true outside a sealed test network is a misconfiguration.
| Variable | Default / Required | Description |
|---|
BTF_TEST_ADMIN_ENABLED | false | ⚠️ Expose test-only admin endpoints. Must remain false in production. |
BTF_TEST_ADMIN_TOKEN | Required if admin enabled | Token required when BTF_TEST_ADMIN_ENABLED=true. Sent in the X-Test-Admin-Token header. Intentionally separate from production auth (test-only surface, no tenant). |
Idempotency
| Variable | Default / Required | Description |
|---|
IDEMPOTENCY_RETRY_WINDOW_SEC | 300 | Time window (in seconds) during which an idempotency key is considered valid. |
Multi-tenancy
| Variable | Default / Required | Description |
|---|
MULTI_TENANT_ENABLED | false | Enable infrastructure-level multi-tenancy with tenant-isolated databases. |
ORGANIZATION_ID | Required (single-tenant + JD polling) | Midaz organization UUID injected into background-worker context (TED IN poller, reconciliation) in single-tenant mode. Required when MULTI_TENANT_ENABLED=false and JD_POLLING_ENABLED=true. Ignored in multi-tenant mode, where per-tenant organization bindings are resolved by the tenant manager. HTTP requests always carry the organization in the X-Organization-Id header instead. |
AWS_REGION | Required if AWS secrets backend | AWS region for per-tenant secret reads from Secrets Manager. Required when MULTI_TENANT_ENABLED=true and the secrets backend is AWS. |
ORGANIZATION_IDS | Required in production | Comma-separated list of Midaz organization UUIDs in the licensing scope. The license gateway validates LICENSE_KEY against these at startup. Also referenced under License. |
MULTI_TENANT_URL | Required when enabled | Tenant Manager HTTP API URL. |
MULTI_TENANT_REDIS_HOST | — | Redis host for Pub/Sub event-driven tenant discovery. |
MULTI_TENANT_REDIS_PORT | 6379 | Redis port for Pub/Sub. |
MULTI_TENANT_REDIS_PASSWORD | — | Redis password for Pub/Sub. |
MULTI_TENANT_REDIS_TLS | false | Enable TLS for Redis Pub/Sub connection. |
MULTI_TENANT_REDIS_CA_CERT | — | CA certificate for the multi-tenant Redis Pub/Sub TLS connection. |
MULTI_TENANT_TIMEOUT | 30 | HTTP timeout in seconds for Tenant Manager API calls. |
MULTI_TENANT_MAX_TENANT_POOLS | 100 | Maximum concurrent tenant database connection pools. |
MULTI_TENANT_IDLE_TIMEOUT_SEC | 300 | Idle timeout in seconds before evicting a tenant pool. |
MULTI_TENANT_CIRCUIT_BREAKER_THRESHOLD | 5 | Number of failures before the circuit breaker opens. |
MULTI_TENANT_CIRCUIT_BREAKER_TIMEOUT_SEC | 30 | Recovery timeout in seconds for the circuit breaker. |
MULTI_TENANT_SERVICE_API_KEY | Required when enabled | API key for the Tenant Manager /settings endpoint. |
MULTI_TENANT_CACHE_TTL_SEC | 120 | In-memory tenant config cache TTL in seconds. Hot-reloadable via systemplane API. |
MULTI_TENANT_CONNECTIONS_CHECK_INTERVAL_SEC | 30 | Async interval in seconds for revalidating pool settings. Bootstrap-only (not hot-reloadable). |
BYOC single-tenant:
# Organization injected into background workers (required when JD polling is enabled)
ORGANIZATION_ID=<your-midaz-organization-uuid>
# Licensing scope validated against LICENSE_KEY in production
ORGANIZATION_IDS=<your-midaz-organization-uuid>
SaaS multi-tenant:
MULTI_TENANT_ENABLED=true
MULTI_TENANT_URL=http://tenant-manager:4003
MULTI_TENANT_SERVICE_API_KEY=your-api-key
MULTI_TENANT_REDIS_HOST=redis.example.com
PostgreSQL
| Variable | Default / Required | Description |
|---|
POSTGRES_HOST | localhost · Required | Primary PostgreSQL host. |
POSTGRES_PORT | 5432 | Primary PostgreSQL port. |
POSTGRES_USER | plugin-br-bank-transfer · Required | Database user. |
POSTGRES_PASSWORD | Required | Database password. Required in production. |
POSTGRES_DB | plugin-br-bank-transfer · Required | Database name. |
POSTGRES_SSLMODE | require | SSL mode. disable is rejected in production. |
POSTGRES_MAX_OPEN_CONNS | 25 | Maximum open connections. |
POSTGRES_MAX_IDLE_CONNS | 5 | Maximum idle connections. |
POSTGRES_CONN_MAX_LIFETIME_MINS | 30 | Connection max lifetime in minutes. |
POSTGRES_CONN_MAX_IDLE_TIME_MINS | 5 | Connection max idle time in minutes. |
POSTGRES_CONNECT_TIMEOUT_SEC | 10 | Connection timeout in seconds. |
PostgreSQL replica
Configure a read replica for query offloading. All fields fall back to primary values when unset.
| Variable | Default / Required | Description |
|---|
POSTGRES_REPLICA_HOST | — | Replica host. Unset = no replica. |
POSTGRES_REPLICA_PORT | — | Replica port. |
POSTGRES_REPLICA_USER | — | Replica user. |
POSTGRES_REPLICA_PASSWORD | — | Replica password. |
POSTGRES_REPLICA_DB | — | Replica database name. |
POSTGRES_REPLICA_SSLMODE | — | Replica SSL mode. |
MongoDB
MongoDB is required for transfer audit event persistence. The service will not start without a valid MongoDB connection.
| Variable | Default / Required | Description |
|---|
MONGO_ENABLED | true · Required | Enable MongoDB connection. Must be true in all environments. |
MONGO_URI | Required | MongoDB connection string (e.g. mongodb://user:pass@host:27017). Must include credentials and TLS in production. |
MONGO_DATABASE | Required | MongoDB database name. |
MONGO_MAX_POOL_SIZE | 25 | Maximum connection pool size. |
MONGO_SERVER_SELECTION_TIMEOUT_MS | 3000 | Server selection timeout in milliseconds. |
MONGO_HEARTBEAT_INTERVAL_MS | 10000 | Heartbeat interval in milliseconds. |
MONGO_TLS_CA_CERT | — | Base64-encoded CA certificate for MongoDB TLS. Use when MongoDB requires TLS with a custom CA (e.g. Atlas, private instances with self-signed certs). |
Redis
| Variable | Default / Required | Description |
|---|
REDIS_HOST | localhost:6379 · Required | Redis host and port. |
REDIS_MASTER_NAME | — | Redis Sentinel master name (if using Sentinel). |
REDIS_PASSWORD | — | Redis password (if auth enabled). |
REDIS_DB | 0 | Redis database number. |
REDIS_PROTOCOL | 3 | Redis protocol version (2 or 3). |
REDIS_TLS | false | Enable TLS for Redis connections. |
REDIS_CA_CERT | — | CA certificate for Redis TLS. |
REDIS_POOL_SIZE | 10 | Connection pool size. |
REDIS_MIN_IDLE_CONNS | 2 | Minimum idle connections. |
REDIS_READ_TIMEOUT_MS | 3000 | Read timeout in milliseconds. |
REDIS_WRITE_TIMEOUT_MS | 3000 | Write timeout in milliseconds. |
REDIS_DIAL_TIMEOUT_MS | 5000 | Dial timeout in milliseconds. |
Redis is a mandatory dependency. If Redis is unavailable at startup or becomes unreachable at runtime, the service reports as DOWN to the orchestration readiness probe and stops accepting requests. Redis is required for idempotency key caching and duplicate detection.
JD SPB connection
These variables are required for BYOC deployments. In SaaS mode, Lerian manages the JD connection.
| Variable | Default / Required | Description |
|---|
JD_BASE_URL | Required for BYOC | JD SPB API base URL. |
JD_SOAP_PATH | /soap | JD SOAP endpoint path. |
JD_LEGACY_CODE | Required for BYOC | JD legacy system code (max 10 chars). |
JD_USER_CODE | Required for BYOC | JD user code (max 10 chars). |
JD_PASSWORD | Required for BYOC | JD password (encrypted at rest). |
JD_PRIVATE_KEY_PEM | Required for BYOC | RSA private key PEM content for XML signature. |
JD_PRIVATE_KEY_PEM_FILE | — | Path to a file containing the RSA private key PEM. Alternative to inlining the key in JD_PRIVATE_KEY_PEM; read at startup. |
JD_PUBLIC_KEY_PEM | — | Public key PEM for validating signatures on JD responses. |
JD_PRIVATE_KEY_KEYINFO | — | XML <KeyInfo> block embedded in the SOAP signature (e.g. base64-encoded X509 cert). Required for the WS-Security envelope when JD demands certificate identification. |
JD_CERT_PEM | — | Optional PEM-encoded X.509 certificate paired with the JD signing key. Used only by the cert-expiry metrics gauge, not the signing path; a malformed PEM is a startup error. |
JD_SIGNING_MODE | local_pem | SOAP signing mode. local_pem signs locally with JD_PRIVATE_KEY_PEM; external_signer delegates to a remote service via JD_EXTERNAL_SIGNER_URL. |
JD_EXTERNAL_SIGNER_URL | Required if JD_SIGNING_MODE=external_signer | Base URL of the external signing service. |
JD_EXTERNAL_SIGNER_AUTH_TOKEN | — | Bearer token sent in the Authorization header for external-signer calls. |
JD_EXTERNAL_SIGNER_TIMEOUT_MS | 5000 | Timeout (in milliseconds) for external-signer calls. |
JD_SANDBOX_MODE | false | Enable JD sandbox mode. Rejected in production. |
JD polling
| Variable | Default / Required | Description |
|---|
JD_POLLING_ENABLED | false | Enable TED IN polling worker. |
JD_POLL_INTERVAL_SECONDS | 60 | How often (in seconds) the plugin polls for incoming TEDs. |
JD_POLLING_ENABLED defaults to false for safer deployments. In single-tenant mode, set ORGANIZATION_ID before enabling it — background workers inject it into context for downstream CRM/Midaz calls. In multi-tenant mode, the TED IN poller manager starts one poller per active tenant discovered through tenant-manager and resolves each tenant’s JD configuration through the tenant integration resolver.
External services (Midaz)
| Variable | Default / Required | Description |
|---|
MIDAZ_BASE_URL | Required | Midaz base service URL. |
MIDAZ_TRANSACTION_URL | Required | Midaz transaction service URL. |
MIDAZ_TIMEOUT_MS | 3000 | Midaz request timeout in milliseconds. |
MIDAZ_MAX_RETRIES | 3 | Retry attempts on Midaz failure. |
MIDAZ_AUTH_ENABLED | false | Enable M2M authentication for Midaz. |
MIDAZ_AUTH_ADDRESS | Required if enabled | Auth service URL for Midaz M2M tokens. |
MIDAZ_CLIENT_ID | Required if enabled | OAuth client ID for Midaz M2M. |
MIDAZ_CLIENT_SECRET | Required if enabled | OAuth client secret for Midaz M2M. |
External services (CRM)
| Variable | Default / Required | Description |
|---|
CRM_BASE_URL | Required | CRM service URL. |
CRM_TIMEOUT_MS | 2000 | CRM request timeout in milliseconds. |
CRM_MAX_RETRIES | 2 | Retry attempts on CRM failure. |
CRM_AUTH_ENABLED | false | Enable M2M authentication for CRM. |
CRM_CLIENT_ID | Required if enabled | OAuth client ID for CRM M2M. |
CRM_CLIENT_SECRET | Required if enabled | OAuth client secret for CRM M2M. |
External services (Fees)
BTF_FEE_ENABLED is the master switch. When false (default), no Fees adapter is constructed and every transfer proceeds with fee=0 with no HTTP call. The other FEES_* variables only take effect when BTF_FEE_ENABLED=true.
| Variable | Default / Required | Description |
|---|
BTF_FEE_ENABLED | false | Master switch for plugin-fees integration. When false, no Fees adapter is built and all transfers run with fee=0 without HTTP calls. Operators running plugin-fees must set this to true explicitly. |
FEES_BASE_URL | Required if enabled | Fees Engine service URL. |
FEES_TIMEOUT_MS | 2000 | Fee request timeout in milliseconds. |
FEES_MAX_RETRIES | 2 | Retry attempts on fee service failure. |
FEES_AUTH_ENABLED | false | Enable M2M authentication for Fees. |
FEES_CLIENT_ID | Required if enabled | OAuth client ID for Fees M2M. |
FEES_CLIENT_SECRET | Required if enabled | OAuth client secret for Fees M2M. |
RabbitMQ
Transfer lifecycle events can be published to RabbitMQ for downstream consumers.
| Variable | Default / Required | Description |
|---|
RABBITMQ_ENABLED | false | Enable transfer lifecycle event publishing. |
RABBITMQ_URL | Required if enabled | AMQP connection URL. Must use amqps:// outside development. |
RABBITMQ_HEALTH_CHECK_URL | — | HTTP(S) URL of the RabbitMQ management health endpoint. Hostname must match RABBITMQ_URL; must use https:// in production. |
RABBITMQ_EXCHANGE | bank_transfer.lifecycle | Exchange name for lifecycle events. |
RABBITMQ_EVENT_SIGNING_SECRET | Required if enabled | HMAC secret for signing published events. Minimum 32 characters. |
Streaming outbox
The streaming subsystem publishes transfer events to a Redpanda/Kafka broker via a transactional outbox. It must be enabled for outbound webhook delivery to work (WEBHOOK_ENABLED=true requires STREAMING_ENABLED=true).
| Variable | Default / Required | Description |
|---|
STREAMING_ENABLED | false | Enable the streaming outbox subsystem. Required for webhook delivery. |
STREAMING_BROKERS | Required if enabled | Comma-separated list of Kafka/Redpanda broker addresses. |
STREAMING_CLIENT_ID | — | Client ID presented to the broker. |
STREAMING_CLOUDEVENTS_SOURCE | Required if enabled | CloudEvents source attribute set on published events. |
STREAMING_OUTBOX_DISPATCH_INTERVAL_SECONDS | 30 | Interval (in seconds) between outbox dispatch cycles. Must be > 0. |
STREAMING_CB_FAILURE_RATIO | 0.5 | Circuit breaker failure ratio that trips the breaker (must be > 0 and ≤ 1). |
STREAMING_CB_MIN_REQUESTS | 10 | Minimum requests in a window before the circuit breaker can trip. |
STREAMING_CB_TIMEOUT_S | 30 | Circuit breaker recovery timeout in seconds. |
STREAMING_CLOSE_TIMEOUT_S | 30 | Graceful shutdown timeout (in seconds) for the streaming producer. |
Webhook delivery
Outbound webhook delivery requires both RabbitMQ and the streaming outbox to be enabled. The webhook worker consumes events from a RabbitMQ queue and delivers them to subscriber endpoints.
| Variable | Default / Required | Description |
|---|
WEBHOOK_ENABLED | false | Enable outbound webhook delivery. Requires RABBITMQ_ENABLED=true and STREAMING_ENABLED=true. |
WEBHOOK_SIGNING_SECRET | Required if enabled | HMAC secret for signing webhook payloads. Minimum 32 characters. |
WEBHOOK_BROKER_EVENT_SIGNING_SECRET | — | Separate HMAC secret for verifying broker events. Falls back to WEBHOOK_SIGNING_SECRET. |
WEBHOOK_QUEUE_NAME | transfer.webhook.delivery | RabbitMQ queue name for webhook events. |
WEBHOOK_DLQ_NAME | transfer.webhook.dlq | Dead-letter queue for failed webhook deliveries. |
WEBHOOK_DLX_EXCHANGE_NAME | — | Dead-letter exchange name. When empty, the worker derives <WEBHOOK_DLQ_NAME>.exchange. Override to centralize the DLX across plugins. |
WEBHOOK_DLQ_MESSAGE_TTL_MS | 0 | x-message-ttl on the DLQ in milliseconds. 0 defers to the library default (7 days). Topology changes require deleting the existing DLQ before redeploy. |
WEBHOOK_DLQ_MAX_LENGTH | 0 | Maximum DLQ message count. 0 defers to the library default (10000). |
WEBHOOK_PREFETCH_COUNT | 20 | RabbitMQ prefetch count. |
WEBHOOK_DELIVERY_CONCURRENCY | 8 | Maximum concurrent webhook deliveries per worker. |
Telemetry (OpenTelemetry)
| Variable | Default / Required | Description |
|---|
ENABLE_TELEMETRY | false | Enable OpenTelemetry tracing and metrics. |
OTEL_EXPORTER_OTLP_ENDPOINT | localhost:4317 | OTel collector gRPC endpoint. |
OTEL_TRACES_SAMPLER_ARG | — | Trace sampling ratio (0.0–1.0). Unset uses the default sampler resolved at telemetry init: 0.1 in production, 1.0 elsewhere. Values outside (0,1] are clamped to 1.0 so misconfiguration cannot silently disable production tracing. |
BTF_METRICS_PROMETHEUS_ENABLED | false | Expose a dedicated Prometheus scrape endpoint for btf.* metrics. When true, the listener at BTF_METRICS_PROMETHEUS_ADDRESS is started. |
BTF_METRICS_PROMETHEUS_ADDRESS | 127.0.0.1:9090 | Listen address for the Prometheus /metrics endpoint. Default binds to loopback so a misconfigured pod does not expose unauthenticated metrics to the cluster network. Override (e.g. 0.0.0.0:9090) only behind a NetworkPolicy or sidecar. |
License
| Variable | Default / Required | Description |
|---|
LICENSE_KEY | Required in production | License key. Required in production environments. |
LICENSE_SERVICE_ADDRESS | — | License validation service URL. |
ORGANIZATION_IDS | Required in production | Same variable as in Multi-tenancy. Comma-separated list of Midaz organization UUIDs in the licensing scope; the license gateway validates LICENSE_KEY against these at startup. |
Encryption
Field-level encryption for sensitive data at rest. Each key must be a base64-encoded 32-byte AES-256 key. Leave empty to disable encryption for that field.
| Variable | Default / Required | Description |
|---|
JD_INCOMING_RAW_XML_ENCRYPTION_KEY | — | AES-256 key for encrypting incoming JD XML payloads. |
RECIPIENT_DETAILS_ENCRYPTION_KEY | — | AES-256 key for encrypting recipient details at rest. |