> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quantumapi.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration reference

> Every CUSTODY_* environment variable accepted by the Qustody API.

This page lists every environment variable read by the `qc-custody` binary, with its default and a one-line description. Source of truth: `custody/config/config.go`.

All variables are prefixed `CUSTODY_`. They may be set in the process environment, in a `.env` file, or via your orchestrator's secret-injection mechanism.

## Server

| Variable                          | Default   | Description                |
| --------------------------------- | --------- | -------------------------- |
| `CUSTODY_SERVER_HOST`             | `0.0.0.0` | Bind address               |
| `CUSTODY_SERVER_PORT`             | `8080`    | HTTP API port              |
| `CUSTODY_METRICS_PORT`            | `9090`    | Prometheus metrics port    |
| `CUSTODY_SERVER_READ_TIMEOUT`     | `30s`     | HTTP read timeout          |
| `CUSTODY_SERVER_WRITE_TIMEOUT`    | `30s`     | HTTP write timeout         |
| `CUSTODY_SERVER_SHUTDOWN_TIMEOUT` | `15s`     | Graceful shutdown deadline |
| `CUSTODY_SERVER_REQUEST_TIMEOUT`  | `30s`     | Per-request timeout        |

## Database

| Variable                          | Default                    | Description                                |
| --------------------------------- | -------------------------- | ------------------------------------------ |
| `CUSTODY_DB_HOST`                 | `localhost`                | PostgreSQL host                            |
| `CUSTODY_DB_PORT`                 | `5432`                     | PostgreSQL port                            |
| `CUSTODY_DB_NAME`                 | `qc_custody`               | Database name                              |
| `CUSTODY_DB_USER`                 | `custody`                  | Database user                              |
| `CUSTODY_DB_PASSWORD`             | (required unless IAM auth) | Database password                          |
| `CUSTODY_DB_SSLMODE`              | `verify-full`              | TLS mode; use `disable` only for local dev |
| `CUSTODY_DB_SSL_ROOT_CERT`        | —                          | Path to CA cert (RDS)                      |
| `CUSTODY_DB_MAX_OPEN_CONNS`       | `25`                       | Pool max                                   |
| `CUSTODY_DB_MAX_IDLE_CONNS`       | `5`                        | Pool idle                                  |
| `CUSTODY_DB_CONN_MAX_LIFETIME`    | `5m`                       | Connection lifetime                        |
| `CUSTODY_DB_MIGRATE_ON_START`     | `true`                     | Auto-run schema migrations                 |
| `CUSTODY_DB_IAM_AUTH`             | `false`                    | Use AWS RDS IAM auth (skips password)      |
| `CUSTODY_DB_READ_REPLICA_ENABLED` | `false`                    | Route reads to replica                     |
| `CUSTODY_DB_READ_HOST`            | —                          | Replica host                               |
| `CUSTODY_DB_READ_PORT`            | `5432`                     | Replica port                               |

## Quantum Chain node

| Variable                             | Default                 | Description                           |
| ------------------------------------ | ----------------------- | ------------------------------------- |
| `CUSTODY_NODE_RPC_URL`               | `http://localhost:8545` | HTTP JSON-RPC endpoint (required)     |
| `CUSTODY_NODE_WS_URL`                | `ws://localhost:8546`   | WebSocket endpoint (deposit watching) |
| `CUSTODY_NODE_BACKUP_RPC_URLS`       | —                       | Comma-separated failover endpoints    |
| `CUSTODY_NODE_DIAL_TIMEOUT`          | `10s`                   | Connection dial timeout               |
| `CUSTODY_NODE_REQUEST_TIMEOUT`       | `15s`                   | Per-request timeout                   |
| `CUSTODY_NODE_HEALTH_CHECK_INTERVAL` | `30s`                   | Health-check cadence                  |

## Chain

| Variable                             | Default | Description                                     |
| ------------------------------------ | ------- | ----------------------------------------------- |
| `CUSTODY_CHAIN_ID`                   | `20803` | Chain ID                                        |
| `CUSTODY_CONFIRMATION_DEPTH`         | `12`    | Blocks before a tx is `CONFIRMED`               |
| `CUSTODY_CONFIRMATION_POLL_INTERVAL` | `5s`    | Confirmation poll interval                      |
| `CUSTODY_SIGNING_PAYLOAD_TTL`        | `10m`   | How long a `PENDING_SIGNATURE` payload is valid |

## Authentication and SSO

| Variable                        | Default  | Description                                        |
| ------------------------------- | -------- | -------------------------------------------------- |
| `CUSTODY_AUTH_ENABLED`          | `true`   | Require bearer auth                                |
| `CUSTODY_WEBHOOK_SIGNING_KEY`   | —        | HMAC key for webhook signatures (required in prod) |
| `CUSTODY_SSO_ENABLED`           | `false`  | Enable SSO/OIDC                                    |
| `CUSTODY_SSO_JWT_SIGNING_KEY`   | —        | HMAC-SHA256 key for SSO tokens (required if SSO)   |
| `CUSTODY_SSO_ACCESS_TOKEN_TTL`  | `15m`    | Access-token lifetime                              |
| `CUSTODY_SSO_REFRESH_TOKEN_TTL` | `24h`    | Refresh-token lifetime                             |
| `CUSTODY_SSO_ALLOWED_ISSUERS`   | —        | Comma-separated OIDC issuer URLs                   |
| `CUSTODY_SSO_AUTO_PROVISION`    | `true`   | Auto-create users on first SSO login               |
| `CUSTODY_SSO_DEFAULT_ROLE`      | `viewer` | Role assigned to auto-provisioned users            |

## Webhooks

| Variable                           | Default | Description                                                                   |
| ---------------------------------- | ------- | ----------------------------------------------------------------------------- |
| `CUSTODY_WEBHOOK_MAX_RETRIES`      | `5`     | Per-delivery retry budget                                                     |
| `CUSTODY_WEBHOOK_RETRY_BASE_DELAY` | `10s`   | Initial backoff                                                               |
| `CUSTODY_WEBHOOK_RETRY_MAX_DELAY`  | `1h`    | Max backoff                                                                   |
| `CUSTODY_WEBHOOK_DELIVERY_TIMEOUT` | `10s`   | Per-delivery HTTP timeout                                                     |
| `CUSTODY_WEBHOOK_WORKER_COUNT`     | `4`     | Concurrent delivery workers                                                   |
| `CUSTODY_WEBHOOK_ENCRYPTION_KEY`   | —       | 64 hex chars (32 bytes) for AES-256-GCM at-rest encryption of webhook secrets |

## Signer

`CUSTODY_SIGNER_*` variables also accept `CUSTODY_ENQLAVE_*` aliases. If both are set, `CUSTODY_SIGNER_*` wins.

| Variable                                | Default    | Description                                             |
| --------------------------------------- | ---------- | ------------------------------------------------------- |
| `CUSTODY_SIGNER_TYPE`                   | `callback` | One of `callback`, `remote`, `grpc`                     |
| `CUSTODY_SIGNER_BACKEND`                | `enqlave`  | `enqlave` or `qey` (only for `grpc`)                    |
| `CUSTODY_SIGNER_ENDPOINT`               | —          | Remote signer HTTPS URL                                 |
| `CUSTODY_SIGNER_API_KEY`                | —          | Remote signer bearer token                              |
| `CUSTODY_SIGNER_GRPC_TARGET`            | —          | Signer gRPC `host:port` (required if type=grpc)         |
| `CUSTODY_SIGNER_GRPC_TLS_CERT`          | —          | Server TLS cert (one-way TLS)                           |
| `CUSTODY_SIGNER_GRPC_CLIENT_CERT`       | —          | Client cert for mTLS                                    |
| `CUSTODY_SIGNER_GRPC_CLIENT_KEY`        | —          | Client private key for mTLS                             |
| `CUSTODY_SIGNER_GRPC_CA_CERT`           | —          | CA cert verifying the signer                            |
| `CUSTODY_SIGNER_GRPC_TIMEOUT`           | `30s`      | Per-call timeout                                        |
| `CUSTODY_SIGNER_GRPC_MAX_RECV_MSG_SIZE` | `0`        | Max gRPC response in bytes (0 = default 64 KB)          |
| `CUSTODY_SIGNER_KEYGEN_MODE`            | `local`    | `local` or `qey` (Qey-side keygen requires backend=qey) |

## RBAC

| Variable                       | Default | Description                       |
| ------------------------------ | ------- | --------------------------------- |
| `CUSTODY_RBAC_ENABLED`         | `false` | Enforce role-based access control |
| `CUSTODY_RBAC_SEED_ON_STARTUP` | `true`  | Seed system roles on first boot   |

## Rate limiting

| Variable                       | Default | Description                             |
| ------------------------------ | ------- | --------------------------------------- |
| `CUSTODY_RATE_LIMIT_ENABLED`   | `true`  | Enable rate limiter                     |
| `CUSTODY_RATE_LIMIT_RPM`       | `120`   | Requests per minute per key             |
| `CUSTODY_RATE_LIMIT_BURST`     | `20`    | Burst size                              |
| `CUSTODY_RATE_LIMIT_REDIS_URL` | —       | Redis URL; enables distributed limiting |

## Telemetry (OpenTelemetry)

| Variable                    | Default      | Description                                |
| --------------------------- | ------------ | ------------------------------------------ |
| `CUSTODY_OTEL_ENABLED`      | `false`      | Emit traces                                |
| `CUSTODY_OTEL_ENDPOINT`     | —            | OTLP endpoint (e.g. `otel-collector:4317`) |
| `CUSTODY_OTEL_SERVICE_NAME` | `qc-custody` | Service name                               |
| `CUSTODY_OTEL_INSECURE`     | `false`      | Disable TLS to collector                   |
| `CUSTODY_OTEL_SAMPLE_RATE`  | `1.0`        | Sample fraction (0.0–1.0)                  |

## Secrets provider

| Variable                     | Default | Description                    |
| ---------------------------- | ------- | ------------------------------ |
| `CUSTODY_SECRETS_PROVIDER`   | `env`   | `env` or `aws`                 |
| `CUSTODY_SECRETS_AWS_REGION` | —       | Region for AWS Secrets Manager |
| `CUSTODY_SECRETS_CACHE_TTL`  | `5m`    | Local cache TTL                |

## Compliance / AML

| Variable                         | Default                                  | Description                                |
| -------------------------------- | ---------------------------------------- | ------------------------------------------ |
| `CUSTODY_COMPLIANCE_ENABLED`     | `false`                                  | Enable AML pre-broadcast screening         |
| `CUSTODY_COMPLIANCE_PROVIDER`    | `noop`                                   | `noop`, `chainalysis`, or `shuftipro`      |
| `CUSTODY_CHAINALYSIS_API_KEY`    | —                                        | Chainalysis API key (required if provider) |
| `CUSTODY_CHAINALYSIS_BASE_URL`   | `https://api.chainalysis.com/api/kyt/v2` | Chainalysis endpoint                       |
| `CUSTODY_CHAINALYSIS_TIMEOUT`    | `30s`                                    | Per-call timeout                           |
| `CUSTODY_SHUFTIPRO_CLIENT_ID`    | —                                        | Shufti Pro client ID                       |
| `CUSTODY_SHUFTIPRO_SECRET_KEY`   | —                                        | Shufti Pro secret                          |
| `CUSTODY_SHUFTIPRO_BASE_URL`     | `https://api.shuftipro.com`              | Shufti Pro endpoint                        |
| `CUSTODY_SHUFTIPRO_CALLBACK_URL` | —                                        | Public URL for async callbacks             |
| `CUSTODY_SHUFTIPRO_TIMEOUT`      | `30s`                                    | Per-call timeout                           |
| `CUSTODY_SHUFTIPRO_ONGOING`      | `false`                                  | Enable ongoing monitoring                  |

## Validation rules

The service refuses to start if:

* `CUSTODY_DB_PASSWORD` is empty and `CUSTODY_DB_IAM_AUTH=false`.
* `CUSTODY_NODE_RPC_URL` is empty.
* `CUSTODY_SSO_ENABLED=true` and `CUSTODY_SSO_JWT_SIGNING_KEY` is empty.
* `CUSTODY_COMPLIANCE_PROVIDER=shuftipro` and either `CUSTODY_SHUFTIPRO_CLIENT_ID` or `CUSTODY_SHUFTIPRO_SECRET_KEY` is empty.
* `CUSTODY_COMPLIANCE_PROVIDER=chainalysis` and `CUSTODY_CHAINALYSIS_API_KEY` is empty.
* `CUSTODY_SIGNER_TYPE=grpc` and `CUSTODY_SIGNER_GRPC_TARGET` is empty.
* `CUSTODY_SIGNER_BACKEND` is not `enqlave` or `qey`.
* `CUSTODY_SIGNER_BACKEND=qey` and `CUSTODY_SIGNER_TYPE` is not `grpc`.
* `CUSTODY_SIGNER_KEYGEN_MODE` is not `local` or `qey`.
* `CUSTODY_SIGNER_KEYGEN_MODE=qey` and `CUSTODY_SIGNER_BACKEND` is not `qey`.
* `CUSTODY_WEBHOOK_ENCRYPTION_KEY` is set but is not exactly 64 hex chars.

## Related

* [Deployment](/qustody/deployment)
* [Errors and codes](/qustody/errors)
* [Security model](/qustody/security-model)
