Environment Variables Reference
Complete, canonical reference for every environment variable PayWarden reads. The source of truth is src/config/env.ts — if this page ever drifts, the Zod schema wins.
PayWarden validates the environment at startup with Zod. Any missing required var or invalid value causes process.exit(1) with a descriptive error.
Copy-paste template
# ── Required ───────────────────────────────────────────────
DATABASE_URL=postgresql://paywarden:localdev123@localhost:5432/paywarden
REDIS_URL=redis://localhost:6379
API_KEY=pw_your_api_key_here # min 10 chars
WEBHOOK_SECRET=whsec_your_secret_here # min 10 chars
VAULT_KEY= # exactly 64 hex chars (openssl rand -hex 32)
HMAC_SECRET= # min 32 chars (openssl rand -hex 32)
ADMIN_PASSWORD= # min 8 chars
JWT_SECRET= # min 32 chars (openssl rand -hex 32)
TRONGRID_API_KEY= # from trongrid.io
USDT_CONTRACT=TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf # Nile testnet USDT
# ── Optional (common) ──────────────────────────────────────
PORT=3000
HOST=0.0.0.0
NODE_ENV=development
LOG_LEVEL=info
TRON_NETWORK=nile
ORDER_TTL=1800
MIN_CONFIRMATIONS=19
SCAN_INTERVAL=3000
SCAN_MODE=address
DEMO_MODE=falseServer
| Variable | Required | Default | Description |
|---|---|---|---|
PORT | no | 3000 | HTTP server port. |
HOST | no | 0.0.0.0 | Bind address for the Fastify server. |
NODE_ENV | no | development | One of development / production / test. |
LOG_LEVEL | no | info | Pino log level: trace / debug / info / warn / error / fatal. |
Database & Redis
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | yes | — | PostgreSQL connection string. Must be a valid URL. |
REDIS_URL | yes | — | Redis connection string. Must be a valid URL. |
Docker Compose defaults:
DATABASE_URL=postgresql://paywarden:localdev123@localhost:5432/paywardenREDIS_URL=redis://localhost:6379
Security
| Variable | Required | Default | Description |
|---|---|---|---|
API_KEY | yes | — | Merchant API authentication key. Minimum 10 chars. Sent as the X-API-Key header. |
WEBHOOK_SECRET | yes | — | Key used to HMAC-SHA256 sign outgoing webhook bodies. Minimum 10 chars. |
VAULT_KEY | yes | — | Exactly 64 hex characters (32 bytes). Encrypts the BIP39 mnemonic stored in the vault/ directory (as vault/seed.enc) with AES-256-GCM. Generate with openssl rand -hex 32. Back it up — loss = vault unrecoverable. |
HMAC_SECRET | yes | — | Minimum 32 chars. Used to HMAC-hash merchant API keys stored in the database. Generate with openssl rand -hex 32. |
Admin Dashboard
Both variables below are required. PayWarden will refuse to start without them.
| Variable | Required | Default | Description |
|---|---|---|---|
ADMIN_PASSWORD | yes | — | Password for /admin login. Minimum 8 chars. |
JWT_SECRET | yes | — | Signs admin-session JWTs. Minimum 32 chars. Generate with openssl rand -hex 32. |
TRON
| Variable | Required | Default | Description |
|---|---|---|---|
TRONGRID_API_KEY | yes | — | Free API key from trongrid.io. |
TRON_NETWORK | no | nile | One of mainnet / nile / shasta. |
USDT_CONTRACT | yes | — | USDT (TRC-20) contract address. Mainnet: TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t. Nile: TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf. |
Payment
| Variable | Required | Default | Description |
|---|---|---|---|
ORDER_TTL | no | 1800 | Seconds an unpaid order stays active before expiring (default = 30 minutes). |
MIN_CONFIRMATIONS | no | 19 | Block confirmations required before an order transitions to confirmed. TRON produces ~1 block / 3s, so 19 ≈ 57s. |
SCAN_INTERVAL | no | 3000 | Chain-watcher polling interval in milliseconds. |
Chain Watcher
| Variable | Required | Default | Description |
|---|---|---|---|
SCAN_MODE | no | address | address polls each pending address individually (best for low volume). block scans every new block for USDT Transfer events (best for > 10 concurrent orders). |
DEMO_MODE | no | false | Boolean (true / 1 to enable). Exposes the /demo checkout route that auto-creates test orders. |
Fund Sweep
Sweeping is disabled unless both HOT_WALLET_KEY and COLD_WALLET_ADDRESS are set.
| Variable | Required | Default | Description |
|---|---|---|---|
HOT_WALLET_KEY | no | — | Hot wallet private key, exactly 64 hex chars. Unset = sweep disabled. |
COLD_WALLET_ADDRESS | no | — | Destination TRON address for swept USDT. Unset = sweep disabled. |
SWEEP_MODE | no | burn | burn or delegate. |
SWEEP_GAS_TOPUP_TRX | no | 20 | TRX amount sent to each payment address before sweeping, to cover energy/bandwidth. |
SWEEP_MIN_USDT | no | 0.5 | Minimum USDT balance on an address that triggers a sweep. |
SWEEP_DELAY_MS | no | 30000 | Delay in milliseconds between confirmation and sweep execution. |
HOT_WALLET_ALERT_TRX | no | 50 | Emit a low-balance alert when hot-wallet TRX drops below this value. |
Alerting / Notifications
All optional. At least one channel should be configured in production so that low-balance, webhook-failed, and sweep-failed events reach an operator. Alerts are de-duplicated per event type for 30 minutes.
| Variable | Required | Default | Description |
|---|---|---|---|
TELEGRAM_BOT_TOKEN | no | — | Bot token from @BotFather. |
TELEGRAM_CHAT_ID | no | — | Target chat ID (user or group). |
SMTP_HOST | no | — | SMTP server host. |
SMTP_PORT | no | 587 | SMTP port. |
SMTP_USER | no | — | SMTP username. |
SMTP_PASS | no | — | SMTP password. |
SMTP_FROM | no | — | From address (falls back to SMTP_USER). |
ALERT_EMAIL_TO | no | — | Destination email address for alerts. |
Proxy & Safety
These toggles guard against IP spoofing, cross-origin abuse, and SSRF. All default to the safe value — do not flip them on unless you understand the consequences.
| Variable | Required | Default | Description |
|---|---|---|---|
TRUST_PROXY | no | false | Trust X-Forwarded-* headers. Set true only when PayWarden is genuinely behind a trusted reverse proxy (Caddy / Nginx) that strips client-supplied X-Forwarded-For. If you enable this while exposing PayWarden directly, any client can spoof their IP and bypass rate limits. |
CORS_ORIGIN | no | — | Comma-separated list of allowed origins, e.g. https://paywarden.io,https://api.paywarden.io. Leave unset to disable CORS entirely. |
ALLOW_PRIVATE_CALLBACKS | no | false | When false, the webhook delivery subsystem rejects any callback_url that resolves to a loopback / RFC1918 / link-local / *.local address. This prevents a stolen API key from turning the webhook fetcher into an internal-network probe (SSRF). Set to true only for local development against http://localhost:4000/webhook style receivers. |
Generating secure values
# VAULT_KEY — most critical, back this up!
openssl rand -hex 32
# HMAC_SECRET, JWT_SECRET
openssl rand -hex 32
# API_KEY, WEBHOOK_SECRET
openssl rand -hex 32