# Stellar Configuration STELLAR_NETWORK=testnet STELLAR_ISSUER_SECRET= # SEP-02 Federation Server # The domain served in federation addresses, e.g. "alice*mobilemoney.com" STELLAR_FEDERATION_DOMAIN=mobilemoney.com # Full base URL of this service (used in stellar.toml FEDERATION_SERVER line) STELLAR_FEDERATION_SERVER_URL=https://api.mobilemoney.com # Other Configuration PORT=3000 NODE_ENV=development DATABASE_URL= REDIS_URL= RATE_LIMIT_WINDOW_MS=900000 RATE_LIMIT_MAX_REQUESTS=100 REQUEST_SIZE_LIMIT=10mb # --------------------------------------------------------------------------- # Response Compression # --------------------------------------------------------------------------- # Enable/disable response compression (default: true) COMPRESSION_ENABLED=true # Compression threshold in bytes - only compress responses larger than this (default: 1024) COMPRESSION_THRESHOLD=1024 # Compression level 1-9, where 1 is fastest and 9 is best compression (default: 6) COMPRESSION_LEVEL=6 # --------------------------------------------------------------------------- # CORS # Cache preflight responses to reduce repeated browser OPTIONS requests. # Value is in seconds. Default: 86400 (24 hours) # --------------------------------------------------------------------------- CORS_MAX_AGE=86400 # --------------------------------------------------------------------------- # Authentication # --------------------------------------------------------------------------- ADMIN_API_KEY=dev-admin-key # --------------------------------------------------------------------------- # Geolocation (ip-api.com — leave blank for free tier, set for pro tier) # --------------------------------------------------------------------------- GEOLOCATION_API_KEY= # Override the base URL if using a different provider (e.g. MaxMind) GEOLOCATION_API_BASE=http://ip-api.com/json # Comma-separated IP prefixes/patterns treated as trusted reverse proxies # (in addition to RFC-1918 ranges which are always trusted) # Example: TRUSTED_PROXY_CIDRS=10.100.0.*,172.20.0.* TRUSTED_PROXY_CIDRS= JWT_SECRET=replace-with-a-secure-shared-secret OAUTH_CLIENT_ID=mobile-money-client OAUTH_CLIENT_SECRET=replace-with-a-secure-client-secret OAUTH_REDIRECT_URI=http://localhost:3000/oauth/callback OAUTH_ISSUER=mobile-money-api OAUTH_AUDIENCE=mobile-money-api OAUTH_JWT_SECRET=replace-with-a-dedicated-oauth-jwt-secret OAUTH_DEFAULT_SCOPE=transactions:read reports:read OAUTH_ACCESS_TOKEN_TTL_SECONDS=3600 OAUTH_REFRESH_TOKEN_TTL_SECONDS=2592000 OAUTH_AUTH_CODE_TTL_SECONDS=300 # ---------------------------------------------------------------------------- # Accounting integrations (QuickBooks / Xero) <-- FIX: added for Xero OAuth 2.0 # ---------------------------------------------------------------------------- # QuickBooks Online OAuth 2.0 QUICKBOOKS_CLIENT_ID= QUICKBOOKS_CLIENT_SECRET= QUICKBOOKS_REDIRECT_URI=http://localhost:3000/api/accounting/auth/quickbooks/callback # Xero OAuth 2.0. The redirect URI MUST exactly match the one registered in the # Xero developer portal and points at GET /api/accounting/xero/callback. XERO_CLIENT_ID= XERO_CLIENT_SECRET= XERO_REDIRECT_URI=http://localhost:3000/api/accounting/xero/callback # Optional: where to send the user's browser after the Xero OAuth handshake. # When unset the callback returns JSON instead of redirecting. XERO_SUCCESS_REDIRECT_URL= XERO_FAILURE_REDIRECT_URL= # --------------------------------------------------------------------------- # OIDC SSO Configuration (Google & Azure AD) -> Issue #521 # --------------------------------------------------------------------------- # Google OAuth2 SSO_GOOGLE_CLIENT_ID= SSO_GOOGLE_CLIENT_SECRET= SSO_GOOGLE_CALLBACK_URL=http://localhost:3000/api/auth/sso/oidc/google/callback # Azure AD (OpenID Connect) SSO_AZURE_OIDC_CLIENT_ID= SSO_AZURE_OIDC_CLIENT_SECRET= SSO_AZURE_OIDC_ISSUER=https://login.microsoftonline.com/YOUR_TENANT_ID SSO_AZURE_OIDC_CALLBACK_URL=http://localhost:3000/api/auth/sso/oidc/azure/callback # --------------------------------------------------------------------------- # Redis (for distributed locks) # --------------------------------------------------------------------------- REDIS_URL=redis://localhost:6379 # --------------------------------------------------------------------------- # Brute Force / Account Lockout # --------------------------------------------------------------------------- # Maximum failed login attempts before the account is temporarily locked. MAX_LOGIN_ATTEMPTS=5 # Sliding window (in minutes) during which failed attempts are counted. LOCKOUT_WINDOW_MINUTES=10 # Duration (in minutes) the account remains locked after the threshold is hit. LOCKOUT_DURATION_MINUTES=30 # Optional: SendGrid template ID for the lockout notification email. # If omitted, an inline HTML fallback is used. SENDGRID_LOCKOUT_TEMPLATE_ID= # --------------------------------------------------------------------------- # Stellar Network # --------------------------------------------------------------------------- STELLAR_NETWORK=testnet # Horizon endpoint(s). Accepts a single URL or a comma-separated list of URLs # (primary first, then fallbacks). Requests automatically fail over to the next # node when the active one is down or rate-limiting us. # Example: https://horizon-testnet.stellar.org,https://horizon-testnet.stellar.example.com STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org # Consecutive failures before a Horizon node is taken out of rotation. HORIZON_MAX_CONSECUTIVE_FAILURES=3 # How long (ms) a node stays out of rotation after being marked down. HORIZON_COOLDOWN_MS=30000 STELLAR_ISSUER_SECRET=YOUR_STELLAR_SECRET_KEY STELLAR_RECEIVING_ACCOUNT=GABC... # Anchor's receiving account for SEP-31 STELLAR_ASSET_CODE=USDC STELLAR_ASSET_ISSUER=G... STELLAR_WEBHOOK_SECRET=your_stellar_webhook_secret # SEP-10 Authentication (Web Auth) # Server signing key for SEP-10 challenge transactions (secret key) STELLAR_SIGNING_KEY= # Domain used in manageData operation key and JWT issuer STELLAR_WEB_AUTH_DOMAIN=https://api.mobilemoney.com # Home domain for multi-domain SEP-10 setups STELLAR_HOME_DOMAIN=mobilemoney.com # Challenge transaction validity in seconds (default: 900 = 15 min) SEP10_CHALLENGE_EXPIRY=900 # JWT token expiration for SEP-10 (default: 1h) SEP10_JWT_EXPIRES_IN=1h # --------------------------------------------------------------------------- # stellar.toml (SEP-01) — Dynamic TOML Generation # --------------------------------------------------------------------------- # Domain used to build server URLs in stellar.toml (no protocol, no trailing slash) STELLAR_FEDERATION_DOMAIN=mobilemoney.com # Base URL of this service (overrides domain-derived defaults for all SEP servers) STELLAR_FEDERATION_SERVER_URL=https://api.mobilemoney.com # Explicit override for the FEDERATION_SERVER line (optional) # STELLAR_FEDERATION_SERVER=https://api.mobilemoney.com/federation # Explicit override for the AUTH_SERVER line (optional — SEP-10) # STELLAR_AUTH_SERVER=https://api.mobilemoney.com/auth # Explicit override for the KYC server (optional — SEP-12) # SEP12_KYC_SERVER=https://api.mobilemoney.com/sep12 # Explicit override for the SEP-24 transfer server (optional) # SEP24_TRANSFER_SERVER=https://api.mobilemoney.com/sep24 # Explicit override for the SEP-31 direct payment server (optional) # SEP31_SERVER=https://api.mobilemoney.com/sep31 # Human-readable description appended to the primary asset CURRENCIES entry STELLAR_ASSET_DESC=USDC stablecoin — anchored 1:1 to USD # Number of decimal places shown by wallets (default: 7) STELLAR_ASSET_DECIMALS=7 # Whether the asset is anchored to an off-chain asset (default: true) STELLAR_ASSET_ANCHORED=true # Off-chain asset type: fiat | crypto | stock | bond | commodity | realestate | other STELLAR_ASSET_ANCHOR_TYPE=fiat # Underlying off-chain asset ticker (default: derived from STELLAR_ASSET_CODE) STELLAR_ASSET_ANCHOR_ASSET=USD # Additional currencies as a JSON array of AssetEntry objects (optional) # STELLAR_EXTRA_ASSETS=[{"code":"EURC","issuer":"G...","status":"live","desc":"Euro Coin"}] # Organisation info for [DOCUMENTATION] section ORG_NAME=Mobile Money Anchor ORG_DBA= ORG_URL=https://mobilemoney.com ORG_LOGO=https://mobilemoney.com/logo.png ORG_DESCRIPTION=Mobile money to Stellar asset anchor ORG_SUPPORT_EMAIL=support@mobilemoney.com # --------------------------------------------------------------------------- # Stellar Channel Accounts Pool (Issue #843) # --------------------------------------------------------------------------- # Channel accounts enable high-throughput concurrent transaction submission # by using multiple accounts to avoid sequence number bottlenecks. # # State is now persisted in the PostgreSQL database. # STELLAR_CHANNEL_ACCOUNTS can optionally be used to seed the DB on first boot # (Format: JSON array like [{"publicKey":"G...","secretKey":"S..."}]) # However, the recommended approach is to use the provisioning script: # npx ts-node src/scripts/provisionChannels.ts --count 10 --balance 3 STELLAR_CHANNEL_ACCOUNTS= # Number of channel accounts to auto-provision (for reference) CHANNEL_POOL_SIZE=10 # Minimum XLM balance per channel account before auto-refund CHANNEL_POOL_MIN_BALANCE=1.5 # Starting balance for newly provisioned channel accounts CHANNEL_POOL_STARTING_BALANCE=3 # Pool Configuration # Maximum time (ms) an account can be locked before auto-release (default: 30000) CHANNEL_POOL_LOCK_TIMEOUT_MS=30000 # Maximum consecutive errors before disabling an account (default: 5) CHANNEL_POOL_MAX_ERRORS=5 # Time (ms) to wait before re-enabling a disabled account (default: 60000) CHANNEL_POOL_RECOVERY_MS=60000 # Maximum queue size for waiting requests (default: 100) CHANNEL_POOL_MAX_QUEUE=100 # Time (ms) to wait in queue before timing out (default: 10000) CHANNEL_POOL_QUEUE_TIMEOUT_MS=10000 # --------------------------------------------------------------------------- # Mobile Money Providers # --------------------------------------------------------------------------- MTN_API_KEY=your_mtn_api_key MTN_API_SECRET=your_mtn_api_secret MTN_SUBSCRIPTION_KEY=your_mtn_subscription_key MTN_BASE_URL=https://sandbox.momodeveloper.mtn.com MTN_TARGET_ENVIRONMENT=sandbox AIRTEL_API_KEY=your_airtel_api_key AIRTEL_API_SECRET=your_airtel_api_secret AIRTEL_BASE_URL=https://openapi.airtel.africa AIRTEL_COUNTRY=NG AIRTEL_CURRENCY=NGN # Airtel Money web-session integration. # Use these when Airtel does not expose a direct REST API in some countries # and a merchant web portal session must be maintained by the backend. AIRTEL_MODE=direct AIRTEL_WEB_BASE_URL=https://airtel-money.example AIRTEL_USERNAME=your_airtel_portal_username AIRTEL_PASSWORD=your_airtel_portal_password AIRTEL_LOGIN_PATH=/login AIRTEL_REFRESH_PATH=/session/refresh AIRTEL_PAYMENT_PATH=/merchant/v1/payments/ AIRTEL_PAYOUT_PATH=/standard/v1/disbursements/ AIRTEL_STATUS_PATH=/standard/v1/payments/:reference AIRTEL_SESSION_STORE_PATH=.airtel-session/session.json AIRTEL_SESSION_TTL_MS=1200000 AIRTEL_REFRESH_SKEW_MS=60000 AIRTEL_MAX_ATTEMPTS=3 # Optional Airtel proxy/wrapper. When configured, Airtel operations are # sent to this proxy instead of using direct API or web-login session adapter. AIRTEL_PROXY_URL= AIRTEL_PROXY_SECRET= # Local provider mock server for offline development. # In Docker development, set MTN_BASE_URL=http://provider-mock:4010/mtn # and AIRTEL_BASE_URL=http://provider-mock:4010/airtel. PROVIDER_MOCK_PORT=4010 PROVIDER_MOCK_DELAY_MS=0 PROVIDER_MOCK_BALANCE=100000 PROVIDER_MOCK_CURRENCY=XAF ORANGE_API_KEY=your_orange_api_key ORANGE_API_SECRET=your_orange_api_secret # Orange Money web-session integration. # Use these when Orange does not expose a direct REST API and a merchant web # portal session must be maintained by the backend. ORANGE_MODE=web ORANGE_WEB_BASE_URL=https://orange-money.example ORANGE_USERNAME=your_orange_portal_username ORANGE_PASSWORD=your_orange_portal_password ORANGE_LOGIN_PATH=/login ORANGE_REFRESH_PATH=/session/refresh ORANGE_PAYMENT_PATH=/transactions/collections ORANGE_PAYOUT_PATH=/transactions/payouts ORANGE_STATUS_PATH=/transactions/:reference ORANGE_SESSION_STORE_PATH=.orange-session/session.json ORANGE_SESSION_TTL_MS=1200000 ORANGE_REFRESH_SKEW_MS=60000 ORANGE_MAX_ATTEMPTS=3 ORANGE_CURRENCY=XAF # Headless browser options for web session mode (to handle JavaScript challenges, CAPTCHAs, etc.) ORANGE_USE_HEADLESS_BROWSER=false ORANGE_HEADLESS=true ORANGE_VIEWPORT_WIDTH=1280 ORANGE_VIEWPORT_HEIGHT=800 ORANGE_USER_AGENT= ORANGE_BROWSER_TIMEOUT_MS=30000 ORANGE_NAVIGATION_TIMEOUT_MS=30000 # Optional direct REST API mode. Set ORANGE_MODE=direct when Orange provides # OAuth client_credentials endpoints instead of a merchant web portal. ORANGE_BASE_URL=https://sandbox.orange.com ORANGE_DIRECT_AUTH_PATH=/oauth/token ORANGE_DIRECT_PAYMENT_PATH=/v1/payments/collect ORANGE_DIRECT_PAYOUT_PATH=/v1/payments/disburse ORANGE_DIRECT_STATUS_PATH=/v1/payments/:reference # Optional scraping-free bridge/proxy. When configured, Orange operations are # sent to this proxy instead of using the web-login session adapter directly. ORANGE_PROXY_URL= ORANGE_PROXY_SECRET= # Failover configuration # Enable automatic provider failover (true/false) PROVIDER_FAILOVER_ENABLED=false # Configure backups using PROVIDER_BACKUP_ variables. Example: # PROVIDER_BACKUP_MTN=airtel # PROVIDER_BACKUP_ORANGE=airtel # Chaos Testing (Staging/Test only) ENABLE_PROVIDER_CHAOS=false CHAOS_LATENCY_CHANCE=0.1 CHAOS_LATENCY_MS=5000 CHAOS_500_CHANCE=0.05 CHAOS_DROP_CHANCE=0.02 # --------------------------------------------------------------------------- # Provider-Specific Transaction Limits (in XAF) # --------------------------------------------------------------------------- # MTN limits (default: 100 - 500,000) MTN_MIN_AMOUNT=100 MTN_MAX_AMOUNT=500000 # Airtel limits (default: 100 - 1,000,000) AIRTEL_MIN_AMOUNT=100 AIRTEL_MAX_AMOUNT=1000000 # Orange limits (default: 500 - 750,000) ORANGE_MIN_AMOUNT=500 ORANGE_MAX_AMOUNT=750000 # --------------------------------------------------------------------------- # Currency / Exchange Rates (exchangerate-api.com) # Free tier: https://www.exchangerate-api.com/ # If unset the service falls back to static approximate rates. # --------------------------------------------------------------------------- EXCHANGE_RATE_API_KEY=your_exchange_rate_api_key # --------------------------------------------------------------------------- # Historical Price Ticker (USD/XLM/XAF) # Runs hourly, stores snapshots in the historical_prices table, and powers # the /api/v1/prices/* endpoints (including 'value at time of transaction'). # --------------------------------------------------------------------------- # Cron expression for the hourly snapshot job. Default: top of every hour. PRICE_TICKER_CRON=0 * * * * # Optional CoinGecko API base (free public API uses /api/v3). COINGECKO_API_BASE=https://api.coingecko.com/api/v3 # Optional CoinGecko demo/pro API key. Sent as x-cg-demo-api-key when set. COINGECKO_API_KEY= # Base URL for exchangerate-api.com (used for USD/XAF since XAF is not a # CoinGecko vs_currency). EXCHANGERATE_API_BASE=https://v6.exchangerate-api.com/v6 # HTTP timeout (ms) for price-provider API calls. PRICE_TICKER_TIMEOUT_MS=10000 # --------------------------------------------------------------------------- # Ingest Stream Token-Bucket Rate Limiter # Applied to all webhook / callback ingest endpoints (MTN, Stellar, generic). # --------------------------------------------------------------------------- # Maximum tokens per bucket (burst ceiling). Default: 100 INGEST_BUCKET_CAPACITY=100 # Tokens refilled per second (steady-state throughput). Default: 50 INGEST_BUCKET_REFILL_RATE=50 # Redis key TTL in seconds for idle buckets. Default: 120 INGEST_BUCKET_KEY_TTL_SEC=120 # --------------------------------------------------------------------------- # Request Timeout # --------------------------------------------------------------------------- REQUEST_TIMEOUT_MS=30000 # KYC Transaction Limits (in XAF - Central African Franc) # These limits enforce daily transaction caps based on user verification levels # Unverified: Basic account with no identity verification LIMIT_UNVERIFIED=10000 # Basic: Account with basic identity verification (ID card, phone number) LIMIT_BASIC=100000 # Full: Account with complete KYC verification (ID, proof of address, selfie) LIMIT_FULL=1000000 # Per-Transaction Amount Limits (in XAF) # These limits prevent individual transactions that are too small or too large # Minimum transaction amount (prevents micro-transactions and spam) MIN_TRANSACTION_AMOUNT=100 # Maximum transaction amount (fraud prevention for single large transactions) MAX_TRANSACTION_AMOUNT=1000000 # --------------------------------------------------------------------------- # AML Monitoring (Anti-Money Laundering) # --------------------------------------------------------------------------- # Flag single transactions greater than this threshold AML_SINGLE_TRANSACTION_THRESHOLD_XAF=1000000 # Flag users whose rolling 24h total exceeds this threshold AML_DAILY_TOTAL_THRESHOLD_XAF=5000000 # Rolling lookback window used for aggregate checks AML_ROLLING_WINDOW_HOURS=24 # Rapid in/out transaction detection window AML_RAPID_WINDOW_MINUTES=15 # Minimum rapid transaction count to trigger structuring alerts AML_RAPID_TRANSACTION_COUNT=3 # Minimum value to consider a transaction as possible structuring AML_STRUCTURING_FLOOR_XAF=100000 # GraphQL (/graphql) — optional in development; required in production (NODE_ENV=production) GRAPHQL_API_KEY= # Optional label for the authenticated principal (returned by the `me` query) GRAPHQL_CLIENT_SUBJECT=api-client # Scheduled Jobs # Cron expressions (defaults shown) CLEANUP_CRON=0 2 * * * REPORT_CRON=0 6 * * * STATUS_CHECK_CRON=0 * * * * ACCOUNT_MERGE_CRON=0 3 * * * # Cleanup: retain completed/failed transactions for this many days (default: 90) LOG_RETENTION_DAYS=90 # Status check: minutes before a pending transaction is considered stuck (default: 60) STUCK_TRANSACTION_MINUTES=60 # Account merge: merge inactive auxiliary Stellar accounts to reclaim base reserves # Comma-separated Stellar secret keys for merge source accounts STELLAR_AUXILIARY_ACCOUNT_SECRETS= # Destination account for merged balances. If unset, the issuer account is used. STELLAR_ACCOUNT_MERGE_DESTINATION= # Number of inactive days required before an auxiliary account is eligible ACCOUNT_MERGE_INACTIVITY_DAYS=30 # Set to true to log merge candidates without submitting transactions ACCOUNT_MERGE_DRY_RUN=false # --- Email Configuration (Nodemailer) --- SMTP_HOST=smtp.ethereal.email SMTP_PORT=587 SMTP_USER=your_smtp_user SMTP_PASS=your_smtp_password EMAIL_FROM="Mobile Money" # --------------------------------------------------------------------------- # AWS S3 Configuration (for KYC document uploads) # --------------------------------------------------------------------------- AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID=your_aws_access_key_id AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key AWS_S3_BUCKET=mobile-money-kyc-documents # KYC Provider Configuration KYC_API_URL=https://api.entrust.com KYC_API_KEY=your_kyc_api_key KYC_WEBHOOK_SECRET=your_webhook_secret # --- Twilio Configuration --- TWILIO_ACCOUNT_SID=your_twilio_account_sid TWILIO_AUTH_TOKEN=your_twilio_auth_token TWILIO_PHONE_NUMBER=your_twilio_sms_number SMS_PROVIDER=twilio # 'twilio' or 'none' # WhatsApp Official API (Twilio) WHATSAPP_ENABLED=false TWILIO_WHATSAPP_NUMBER=whatsapp:+14155238886 TWILIO_WHATSAPP_TRANSACTION_TEMPLATE_SID=HX... TWILIO_WHATSAPP_OTP_TEMPLATE_SID=HX... USE_HTTP2=false # Set to true with valid certs to enable HTTP/2 # Support Ticket Integration (Zendesk/Intercom) # Provider selection: 'zendesk', 'intercom', or 'both' SUPPORT_PROVIDER=zendesk # Zendesk Configuration ZENDESK_SUBDOMAIN=your-company ZENDESK_API_TOKEN=your_zendesk_api_token ZENDESK_USER_EMAIL=support@yourcompany.com # Optional: Default group ID for routing dispute tickets ZENDESK_GROUP_ID= # Optional: Default assignee ID for dispute tickets ZENDESK_ASSIGNEE_ID= # Intercom Configuration INTERCOM_ACCESS_TOKEN=your_intercom_access_token # Optional: Admin ID for sending messages INTERCOM_ADMIN_ID= # Support API Timeout and Retry Configuration SUPPORT_API_TIMEOUT_MS=10000 SUPPORT_RETRY_ATTEMPTS=3 SUPPORT_RETRY_DELAY_MS=1000 # Refresh Token REFRESH_TOKEN_EXPIRES_IN= REFRESH_TOKEN_SECRET= REFRESH_TOKEN_ISSUER= # --------------------------------------------------------------------------- # Mock Provider Server Configuration # Used for development and testing with mock MTN/Airtel providers # --------------------------------------------------------------------------- # Delay in milliseconds before firing webhook callbacks - simulates realistic # network latency and provider behavior when webhooks are delivered (default: 3000ms) MOCK_WEBHOOK_LATENCY_MS=3000 # Whether webhook latency simulation is enabled. Set to false to fire webhooks # immediately without delay. (default: true) MOCK_WEBHOOK_LATENCY_ENABLED=true # --------------------------------------------------------------------------- # Provider Health Check # --------------------------------------------------------------------------- # Cron schedule for provider health checks (default: every 5 minutes) PROVIDER_HEALTH_CHECK_CRON=*/5 * * * * # Webhook URLs for provider health alerts (comma-separated or individual) PROVIDER_HEALTH_WEBHOOK_URL= # --------------------------------------------------------------------------- # PII Encryption (AES-256-GCM) # --------------------------------------------------------------------------- # Global key material for encrypting PII fields (name, address, id_number). # Must be a high-entropy secret (>=32 chars). Never commit real values. # Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" DB_ENCRYPTION_KEY=replace-with-a-secure-32-char-key # Master key for per-user HKDF key derivation. Keep separate from DB_ENCRYPTION_KEY. PII_MASTER_KEY=replace-with-a-different-secure-32-char-key # --------------------------------------------------------------------------- # Automatic Persisted Queries (APQ) # --------------------------------------------------------------------------- # TTL in seconds for APQ hash→query entries stored in Redis (default: 86400 = 24h) APQ_TTL_SECONDS=86400 # --------------------------------------------------------------------------- # GraphQL Subscriptions (Redis PubSub) # --------------------------------------------------------------------------- # REDIS_URL is already used above — the same instance is used for PubSub. # JWT_SECRET is required for authenticating WebSocket connections. # Clients must pass: connectionParams: { authToken: "" } JWT_SECRET=replace-with-a-secure-jwt-secret # Provider balance cache TTL (seconds) PROVIDER_BALANCE_CACHE_TTL=60 # --------------------------------------------------------------------------- # Accounting Integrations (QuickBooks & Xero) # --------------------------------------------------------------------------- QUICKBOOKS_CLIENT_ID=your_quickbooks_client_id QUICKBOOKS_CLIENT_SECRET=your_quickbooks_client_secret QUICKBOOKS_REDIRECT_URI=http://localhost:3000/api/accounting/quickbooks/callback XERO_CLIENT_ID=your_xero_client_id XERO_CLIENT_SECRET=your_xero_client_secret XERO_REDIRECT_URI=http://localhost:3000/api/accounting/xero/callback # --------------------------------------------------------------------------- # Centralized Error Tracking — Sentry (feature/sentry-integration) # --------------------------------------------------------------------------- # The Sentry DSN for the Go ingest service and other components. # Leave blank to disable Sentry. SENTRY_DSN= # --------------------------------------------------------------------------- # Centralized Logging — Loki Transport (feature/centralized-logging) # --------------------------------------------------------------------------- # All variables below are OPTIONAL. When unset the application falls back to # stdout-only logging so CI and local dev work without any external sink. # Full URL of the Loki push endpoint, e.g. http://loki:3100 # Leave blank to disable the Loki transport (stdout only). LOKI_HOST= # Override the service name label attached to every log line (default: mobile-money-api) SERVICE_NAME=mobile-money-api # Log level threshold (default: info). Valid: trace | debug | info | warn | error | fatal LOG_LEVEL=info # Log file path for the ECS structured logger mirror (default: logs/app.log) # Set to /dev/null to disable file mirroring. LOG_FILE_PATH=logs/app.log # Local log sharding policy (development and sandbox only) # Maximum size before the active log file rolls into a new shard. LOG_SHARD_MAX_BYTES=5242880 # Compress rotated shards as .gz to keep local log volume small. LOG_SHARD_COMPRESS=true # Remove compressed shards older than this many days. LOG_SHARD_RETENTION_DAYS=7 # --------------------------------------------------------------------------- # Dedicated Sandbox Environment # --------------------------------------------------------------------------- IS_SANDBOX=false SANDBOX_DATABASE_URL=postgresql://user:password@localhost:5432/mobile_money_sandbox?schema=public