Environment variables
Full reference for the backend and Admin Panel. Source of truth for local dev is backend/.env.example; live values are Railway variables per environment, never committed to either repo.
⚠
Never put a real value for anything marked secret in a file, chat message, or this wiki. Set secrets directly in the Railway dashboard or via railway variables --set. .railway/railway.ts keeps every secret as preserve() — literal values live only in Railway.
shared = same value in both testing and production today. per-env = deliberately different per environment. This is the current state, not a rule — see Third-party services for which shared ones are expected to split later (payment keys).
Core & environment identity
| Variable | Purpose | Status |
ENVIRONMENT | Gates environment-specific behavior in code — e.g. disables the free-wallet-credit Test Store endpoint when set to production | per-env — staging / production |
APP_NAME | Display name used in a few backend responses | shared |
API_V1_PREFIX | API route prefix, default /api/v1 | shared |
DATABASE_URL | Postgres connection string (asyncpg form) | per-env secret — points at each environment's own database |
DB_AUTO_CREATE_TABLES | Create tables on startup if missing | shared |
Auth & Admin cookies
| Variable | Purpose | Status |
JWT_SECRET_KEY | Signs User/Host access & refresh tokens | shared secret |
JWT_ALGORITHM | Default HS256 | shared |
ACCESS_TOKEN_EXPIRE_MINUTES / REFRESH_TOKEN_EXPIRE_DAYS | Token lifetimes | shared |
ADMIN_API_TOKEN | Admin service-to-service auth | shared secret |
ADMIN_PANEL_ORIGIN | Expected Admin Panel origin (currently unused by CORS — CORS_ALLOWED_ORIGINS is *) | per-env — the Admin Panel URL for that environment |
ADMIN_ACCESS_COOKIE_NAME / ADMIN_CSRF_COOKIE_NAME | Cookie names for Admin session/CSRF | shared |
ADMIN_COOKIE_SECURE | Require HTTPS-only cookies | shared — false on backend, true on admin-panel in both environments (pre-existing asymmetry, not something this wiki fixed) |
ADMIN_LOGIN_MAX_ATTEMPTS / ADMIN_LOGIN_WINDOW_MINUTES | Admin login rate limiting | shared |
AUTH_RATE_LIMIT_MAX_ATTEMPTS / AUTH_RATE_LIMIT_WINDOW_SECONDS | User/Host auth rate limiting | shared |
OTP_* (cooldown, max per day/IP/global, lockout, code validity, allowed country codes) | OTP send/verify throttling | shared |
TRUSTED_PROXY_HOPS | How many reverse-proxy hops to trust for client IP | shared |
Firebase
| Variable | Purpose | Status |
FIREBASE_PROJECT_ID / FIREBASE_SERVICE_ACCOUNT_PATH / FIREBASE_SERVICE_ACCOUNT_JSON / FIREBASE_CHECK_REVOKED | User App's Firebase Admin credentials (project vibeconnect-7c601) | shared secret |
HOST_FIREBASE_PROJECT_ID / HOST_FIREBASE_SERVICE_ACCOUNT_PATH / HOST_FIREBASE_SERVICE_ACCOUNT_JSON / HOST_FIREBASE_CHECK_REVOKED | Host App's Firebase Admin credentials (project hostvibeconnect) | shared secret |
These are the backend's Firebase Admin credentials (token verification, server-side push) — separate from the client apps' Firebase config, which is per build-flavor; see App identifiers.
OTP provider
| Variable | Purpose | Status |
MSG91_AUTHKEY | Alternate OTP provider to Firebase, selectable per-app from Admin Panel (App Config → OTP Provider). Only required when that toggle is set to msg91 — the widget's own ID/token are Admin-managed, not env vars | shared secret |
Public URLs & CORS
| Variable | Purpose | Status |
CORS_ALLOWED_ORIGINS | Allowed CORS origins for the API | shared — currently * in both environments |
PUBLIC_SITE_BASE_URL | Base URL used to build public links — legal document pages (privacy policy, terms, etc.) and the Cashfree payment return URL | per-env — that environment's own backend URL |
DAILY_MEET_API_BASE_URL (Admin Panel service, not backend) | Which backend the Admin Panel proxies requests to | per-env |
Calls, RTC & realtime
| Variable | Purpose | Status |
AGORA_APP_ID / AGORA_APP_CERTIFICATE | Agora call provider | shared secret (App ID itself isn't secret, certificate is) |
AGORA_RTC_TOKEN_TTL_SECONDS / AGORA_RTC_TOKEN_REFRESH_THRESHOLD_SECONDS | Agora token lifetime/refresh window | shared |
STREAM_API_KEY / STREAM_SECRET_KEY | GetStream Video — used for video calls only, until the self-hosted WebRTC video path is fixed (audio calls use webrtc/Agora) | shared secret |
CLOUDFLARE_TURN_KEY_ID / CLOUDFLARE_TURN_API_TOKEN / CLOUDFLARE_TURN_CREDENTIAL_TTL_SECONDS | Preferred TURN path for the self-hosted webrtc provider | shared secret |
RTC_SIGNALING_TOKEN_TTL_SECONDS | Signaling JWT lifetime for self-hosted WebRTC | shared |
CALL_RINGING_TIMEOUT_SECONDS / CALL_RECONNECT_GRACE_SECONDS / CALL_CONNECT_TIMEOUT_SECONDS / CALL_HEARTBEAT_TIMEOUT_SECONDS | Call lifecycle timeouts | shared |
CALL_BILLING_SWEEP_ENABLED / CALL_BILLING_SWEEP_INTERVAL_SECONDS | Background call-billing worker | shared |
CHAT_RECHARGE_GRACE_SECONDS | Grace period for low-balance chat | shared |
MODERATION_EVIDENCE_MAX_CHARACTERS / MODERATION_DEDUPLICATION_WINDOW_SECONDS | Call Safety text moderation limits | shared |
Payments
| Variable | Purpose | Status |
RAZORPAY_KEY_ID / RAZORPAY_KEY_SECRET / RAZORPAY_WEBHOOK_SECRET | Razorpay recharge provider — mode is auto-detected from the key prefix (rzp_test_ vs rzp_live_), no separate flag | expected to split, currently shared secret — production still holds testing's sandbox keys |
CASHFREE_APP_ID / CASHFREE_SECRET_KEY / CASHFREE_WEBHOOK_SECRET | Cashfree recharge provider | expected to split, currently shared secret — same as Razorpay |
CASHFREE_ENVIRONMENT | Explicit sandbox/production flag (Cashfree app IDs aren't prefix-distinguishable the way Razorpay's are) | expected to split, currently shared — sandbox in both environments today |
REVENUECAT_WEBHOOK_AUTHORIZATION | Validates incoming RevenueCat/IAP webhooks | shared secret |
Security
| Variable | Purpose | Status |
BANK_ENCRYPTION_KEY | Encrypts Host payout bank account numbers at rest | shared secret |
Private documents (KYC, proofs)
| Variable | Purpose | Status |
PRIVATE_DOCUMENT_STORAGE_BACKEND / PRIVATE_DOCUMENT_STORAGE_PATH | Where KYC/proof files live — local filesystem backend, backed by the private-documents Railway volume | shared in config; the underlying volume is per-environment (each environment has its own) |
PRIVATE_DOCUMENT_SIGNED_URL_TTL_SECONDS | How long a signed access URL is valid | shared |
PRIVATE_DOCUMENT_MAX_BYTES / PRIVATE_DOCUMENT_ALLOWED_CONTENT_TYPES | Upload limits | shared |
Cleanup & retention
| Variable | Purpose | Status |
CLEANUP_ON_STARTUP | Run cleanup routines on boot | shared — false |
DOCUMENT_RETENTION_DAYS / NOTIFICATION_RETENTION_DAYS / DEVICE_TOKEN_STALE_DAYS | How long old records are kept before cleanup | shared |
ACCOUNT_DELETION_SWEEP_ENABLED / ACCOUNT_DELETION_SWEEP_INTERVAL_SECONDS | Background account-deletion worker | shared |
Full source
backend/.env.example is the canonical, commented list for local development — this page mirrors it plus the live Railway per-environment facts. If they ever disagree, trust .env.example for what a variable does and railway variables --service <name> --environment <env> for its current live value.