Appearance
Environment variables
Grouped by concern. Secrets are marked; never put a marked variable in a frontend bundle, a commit, or a log line.
.env on the production VM is never overwritten by a deploy
deploy.gcp.sh excludes .env from the rsync. New variables must be added on the VM manually, then the process restarted. Forgetting this is the most common cause of "the code deployed but the feature does not work".
bz-backend — core
| Variable | Purpose |
|---|---|
PORT | Listen port (5000) |
NODE_ENV | production on the VM |
MONGO_URI / MONGO_URL | MongoDB Atlas connection string |
MONGO_DB_NAME, MONGO_TOKEN_DB_NAME | Database names |
REDIS_URL | Redis connection |
DISABLE_REDIS | Force the in-memory fallback |
CRON | Set to false to disable every cron. Anything else enables them |
AGENT_URL | Where bz-agent lives (http://localhost:4000) |
FRONTEND_URL, ADMIN_FRONTEND_URL, APP_BASE_URL, CALLBACK_BASE_URL | Link and redirect bases |
JWT_SECRET, JWT_ADMIN_SECRET 🔒 | Token signing |
ADMIN_SECRET 🔒 | Admin gate |
ENCRYPTION_KEY, ENCRYPTION_MASTER_KEY 🔒 | At-rest encryption |
SENTRY_DSN | Error reporting |
ENABLE_MONITORING, LOG_TARGET, LOG_TARGETS | Observability |
CRON=false in a local .env is strongly recommended
Local dev points at production Atlas by default. With crons enabled, your laptop becomes a second CSIP and Autopilot executor competing with production — submitting duplicate transactions with the same keys. See local development.
Signing keys 🔒
| Variable | Address | Role |
|---|---|---|
TX_SIGNER | 0x75a8b522FC3195e3a3570F11f111AC89c0D35975 | Signs relayer meta-transactions on all chains except Polygon; also the relayer owner |
POL_TX_SIGNER | — | Polygon-specific signer (chain 137) |
PRIVATE_KEY_EXECUTOR | 0x5935745431D1385ae1a9CE2644fb5f5d1f140459 | CSIP + Autopilot executor; also DCA vault owner |
BACKEND_PRIVATE_KEY | 0x2Ed05570214f6C0F7612B580aB37C163076e0162 | Autopilot vault owner and deployer |
BACKEND_SIGNER_PRIVATE_KEY | — | Backend attestations |
AUTOPILOT_EXECUTOR_KEY | — | Autopilot-specific executor override |
DCA_OWNER_KEY | — | Used by the DCA upgrade script (hardhat network arbitrum_dca_owner) |
PRIVATE_KEY, PRIVATE_KEY1 | — | Legacy deploy keys |
PRESALE_MASTER_SEED 🔒 | — | Presale wallet derivation |
CLIPPERS_PAYOUT_PRIVATE_KEY 🔒 | — | Creator payouts |
PRIVATE_KEY_CHANGELLY, CHANGELLY_PRIVATE_KEY 🔒 | — | Changelly request signing |
Contract addresses
| Variable | Default |
|---|---|
AUTOPILOT_ADDRESS_ARBITRUM | 0x689AaEc7E3012d84226e7c5F4DEeFdC01C86d23e |
AUTOPILOT_ADDRESS_BASE | (empty — cron skips) |
AUTOPILOT_ADDRESS_ROBINHOOD | 0x4dE7CD522f1715b2a48F3ad6612924841d450A0F |
TREASURY_ADDRESS, TREASURY_WALLET | — |
NFT_STAKING_ADDRESS, BZ_NFT_STAKING_ADDRESS | — |
MARKETPLACE_CONTRACT_ADDRESS, MARKETPLACE_NFT_ADDRESS | — |
POLYGON_CLAIM_CONTRACT, QUBETICS_CLAIM_CONTRACT, MONAD_CLAIM_CONTRACT_ADDRESS, MONAD_CHAIN_ID | — |
{ARBITRUM,BASE,BSC,LINEA}_DEPOSIT_CONTRACT | — |
{ARBITRUM,BASE,BSC,LINEA}_{USDC,USDT,DAI}_ADDRESS | Stablecoin addresses per chain |
RPC URLs
| Variable | Chain |
|---|---|
DEFAULT_RPC_URL | Fallback |
ETHEREUM_RPC_URL | 1 |
ARBITRUM_RPC_URL | 42161 |
ARBITRUM_SEPOLIA_RPC_URL | 421614 |
BASE_RPC_URL | 8453 |
BSC_RPC_URL, BSC_TESTNET_RPC_URL | 56 |
POLYGON_RPC_URL | 137 |
QUBETICS_RPC_URL | Qubetics |
Most chains get their RPC from Mongo, not from env
Network.metamask.rpcUrls[0] is the source for signing, the fee summary and vault interaction. These env vars cover the chains where automation and deployment scripts need a direct URL. A dead RPC in the Mongo record takes that chain down silently.
Aggregator / provider keys 🔒
| Variable | Provider |
|---|---|
ONE_INCH_KEY | 1inch |
OPEN_OCEAN_API_KEY, OPEN_OCEAN_REFERRER | OpenOcean — also supplies gas prices |
UNIZEN_API_KEY | Unizen |
ODOS_API_KEY | Odos |
OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE, OKX_PROJECT_ID, OKX_API_URL | OKX |
UNISWAP_API_KEY, UNISWAP_API_URL | Uniswap |
RELAY_API_KEY | Relay |
RANGO_API_KEY | Rango |
ACROSS_API_KEY, ACROSS_INTEGRATOR_ID | Across |
NEAR_1CLICK_API_KEY | Near 1Click |
GASZIP_API_URL | GasZip |
RHINO_API_KEY, RHINO_API_URL | RhinoFi |
HOUDINI_API_KEY | Houdini |
CHANGE_NOW_API_KEY | ChangeNow |
SWAP_SDK_BASE_URL | Override the SDK's baseApiUrl |
KIMA_BACKEND_URL | Defaults to https://kima.blazpay.com |
Squid's integrator id (blazpay-db534a27-fefd-4504-b5bd-a7e6407bd656) and 1inch's referrer (0x5222…1D35) are hardcoded in their controllers.
Fiat ramp keys 🔒
| Variable | Provider |
|---|---|
SECRET_KEY_ONRAMP | OnRamp.money |
SECRET_KEY_ALCHEMY | AlchemyPay |
CHANGELLY_PRIVATE_KEY, PRIVATE_KEY_CHANGELLY | Changelly |
Transak and MoonPay use public catalogue endpoints; check their controllers before assuming no key is needed.
Explorer / data APIs 🔒
| Variable | Purpose |
|---|---|
ETHERSCAN_API_KEY | Etherscan v2 unified — one key, all chains. Used by the auditor, token safety, approval scan and wallet card |
ARBISCAN_API_KEY, BSCSCAN_API_KEY, POLYGONSCAN_API_KEY, BASESCAN_API_KEY, OPSCAN_API_KEY | Per-chain verification |
COINMARKETCAP_API_KEY, _2, _3 | Autopilot price series — three keys for rate-limit headroom |
MORALIS_API_KEY, _2, _3 | Balance lookups |
OPENSEA_KEY | NFT metadata |
CoinGecko (fee summary) and Zerion (portfolio) are called without a key in the current code.
Model providers 🔒
Blazpay's intent engine addresses models by tier, not by vendor — see agent graph. These variables are the credentials and overrides behind those tiers. The variable names are what they are in code; the prose in these docs deliberately refers to roles instead.
| Variable | Role |
|---|---|
OPENAI_API_KEY | Credential for the audit and token-safety models |
GROQ_API_KEY, GROQ_MODEL | Credential + model for Autopilot policy drafting |
AUTOPILOT_LLM_MODEL | Model override for Autopilot drafting |
LLM_BASE_URL | Point a tier at a self-hosted or alternate endpoint |
GOOGLE_SERVICE_ACCOUNT | Managed-provider service account |
RASA_ENDPOINT, RASA_TOKEN | Self-hosted Rasa NLU service (legacy swap-ai chat path) |
WIT_TOKEN | wit.ai NLU (legacy) |
STREAM_TOKEN_DELAY_MS | Artificial SSE token pacing |
Repointing a tier
LLM_BASE_URL plus the LLM_MODEL_* overrides are the seam for moving a tier onto self-hosted inference without touching bz-agent. The Rasa service is already self-hosted and is the precedent for running NLU in-house.
bz-agent
| Variable | Purpose |
|---|---|
LLM_OPENAI_API_KEY 🔒 (falls back to OPENAI_API_KEY) | Credential for the extraction tier |
LLM_MODEL_EXTRACTION | Model serving the extraction tier |
LLM_MODEL_CONVERSATION | Model serving the conversation tier |
LLM_MODEL_COMPLEX | Model serving the complex tier |
LLM_GOOGLE_PROJECT_ID | Managed conversation provider — project |
LLM_GOOGLE_CLIENT_EMAIL | Managed conversation provider — service account |
LLM_GOOGLE_PRIVATE_KEY 🔒 | PEM with \n escapes |
LLM_GOOGLE_PRIVATE_KEY_ID, LLM_GOOGLE_CLIENT_ID | Optional |
Plus Mongo, PostgreSQL (PGVector) and Redis connection strings.
All three Google variables or none
getConversationLLM() requires LLM_GOOGLE_PROJECT_ID, LLM_GOOGLE_CLIENT_EMAIL and LLM_GOOGLE_PRIVATE_KEY. With any one missing it silently falls back to the extraction model instead of the conversation tier. Answer quality degrades with no error.
Storage & media 🔒
| Variable | Service |
|---|---|
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_BUCKET_NAME | S3 |
AWS_KEY_ID_KMS | KMS key for Orderly ed25519 encryption |
AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY, AWS_SES_REGION, AWS_SES_ENDPOINT, AWS_SES_FROM_ADDRESS | |
CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET | Images |
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC_URL, R2_MEDIA_BUCKET_NAME, R2_MEDIA_PUBLIC_URL | Cloudflare R2 |
PINATA_JWT | IPFS pinning |
NFT_IMAGE_BASE_URL, NFT_METADATA_API | NFT assets |
Messaging & community 🔒
| Variable | Service |
|---|---|
TELEGRAM_BOT, TELEGRAM_BOT_TOKEN, TELEGRAM_ALERTS_CHAT_ID, COMMUNICATION_TELEGRAM_BOT_TOKEN | Telegram |
DISCORD_BOT_TOKEN, DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, DISCORD_2X_BOOSTER_ROLE_ID | Discord |
EMAIL_USER, EMAIL_PASSWORD, ZOHO_EMAIL_USER, ZOHO_EMAIL_PASSWORD | SMTP |
GALXE_API_KEY, ZEALY_API_KEY, INTRACT_API_KEY, SMM_API_KEY | Quest platforms |
APIFY_API_TOKEN, APIFY_ACTOR_ID | Scraping |
BOLT_API_KEY | — |
Feature flags & tuning
| Variable | Effect |
|---|---|
AUDIT_PUBLIC_BASE_URL | Share-link prefix. Defaults to https://audit.blazpay.ai |
DISABLE_BRIDGE_STATUS_CRON | Disable just that cron |
CSP_ENABLED | Content-Security-Policy |
STAKE_RETRY | Staking retry behaviour |
USE_LEGACY_REWARDS | Rewards path selection |
REWARDS_HUB_FORCE_PROXY, REWARDS_HUB_PROXY_GROUPS, REWARDS_HUB_PROXY_PREFIXES, REWARDS_ADMIN_FORCE_PROXY, REWARDS_ADMIN_PROXY_GROUPS, REWARDS_ADMIN_NATIVE_WRITE_GROUPS, THREADS_FORCE_PROXY, THREADS_PROXY_GROUPS | Microservice routing toggles |
POKER_PLATFORM_FEE_ENABLED, POKER_PLATFORM_FEE_BPS, POKER_FEE_TO, POKER_ESCROW_TO | Poker economics |
PREDICTION_MIN_STAKE, PREDICTION_MAX_STAKE, PREDICTION_DAILY_LIMIT, PREDICTION_LOCK_BEFORE_END_SECONDS, PREDICTION_{MIN,MAX}_{UP,DOWN}_POOL, PREDICTION_SEED_ENABLED, PREDICTION_FAKE_PARTICIPANTS | Prediction market tuning |
BINANCE_PROXY_URL | Price proxy |
ARB_GAMES_KEY | Games |
PREDICTION_FAKE_PARTICIPANTS and PREDICTION_SEED_ENABLED
These seed synthetic participants into prediction markets. Whatever the product rationale, know that they exist before making claims about market depth.
defi-dex (frontend)
Only VITE_-prefixed variables reach the bundle. Never put a secret here.
| Variable | Purpose |
|---|---|
VITE_SITE | defi | ai — picks the app shell. Inlined, so Rollup tree-shakes the other |
VITE_API_URL | API base. Falls back to http://localhost:5000/api on localhost, https://api.blazpay.com/api otherwise |
VITE_GA_MEASUREMENT_ID | GA4. Analytics is a no-op without it |
.env.ai holds the AI-site build's values; netlify.toml and netlify.ai.toml hold the per-site production values.
System settings (not env)
Runtime-tunable values live in Mongo, not the environment:
js
await SystemSetting.getValue('audit_free_limit_per_wallet') // default 3
await SystemSetting.setValue('audit_free_limit_per_wallet', 5)
await SystemSetting.getByCategory('limits')Categories: bridge, security, network, fees, limits, general. Four Autopilot settings are seeded by scripts/seed-autopilot-settings.js.
Prefer a system setting over a new env var
Changing an env var needs an SSH session and a process restart. Changing a system setting is a database write. Use env vars for secrets and infrastructure; use system settings for limits and flags.
Auditing your environment
bash
# Which env vars does the code actually read?
grep -rhoE 'process\.env\.[A-Z0-9_]+' --include='*.js' \
controllers services utils middleware v1 routes index.js \
| sed 's/process\.env\.//' | sort -uRun it from bz-backend. Note that archive/, new-backend/ and microservices-backend/ are not mounted, so exclude them — they contribute variables nothing reads.