# HTTP port (default: 3003) # PORT=3003 # Endorser API base URL (default: https://api.endorser.ch) # ENDORSER_URL=https://api.endorser.ch # DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch # Partner API base URL (default: https://partner-api.endorser.ch) # PARTNER_URL=https://partner-api.endorser.ch # DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch # Firebase Admin (required for WAKEUP_PING and AlertSearch FCM). # Path 1: inline service account JSON (one line). The application reads this variable. # FIREBASE_SERVICE_ACCOUNT_JSON={"type":"service_account",...} # Path 2: if unset/empty, Application Default Credentials (ADC). # ADC may use GOOGLE_APPLICATION_CREDENTIALS; the application does not read that name itself. # Durable directory for SQLite: notify.sqlite plus -wal/-shm while running (default: ./data). # In production this must be persistent storage (Docker: volume on /app/data). # NOTIFY_DATA_DIR=./data # Do not set NODE_ENV=test-local in production (bypasses ethr JWT expiry). # NODE_ENV=test-local # Mount the /debug router (device lookup, manual wakeup send). Default: false. # Leave off in production; the routes expose per-device state to any accepted JWT. # DEBUG_ENDPOINT=false # --- SMS notifications (/notify-sms) --- # Master switch. While false, every /notify-sms route returns 503 SMS_DISABLED # and the SMS scheduler does not start. # SMS_ENABLED=false # HMAC key for verification codes and phone hashes. Required when SMS_ENABLED; # the process refuses to start without it. Rotating it invalidates every pending # code and orphans every stored phone_hash. # SMS_CODE_SECRET= # Twilio. Sends fail with SMS_NOT_CONFIGURED until the account, the token, and # one of the two "from" values are all present. # TWILIO_ACCOUNT_SID= # TWILIO_AUTH_TOKEN= # Identifier for sender whom this is from. # Prefer the Messaging Service once an A2P 10DLC campaign is approved: the # campaign lives on it, and it wins when both are set. # TWILIO_MESSAGING_SERVICE_SID= # TWILIO_FROM_NUMBER=+15550000000 # The public URL Twilio posts /notify-sms/inbound to. Twilio signs that exact # string, and behind a proxy or tunnel the request headers do not reproduce it. # TWILIO_WEBHOOK_URL=https://example.com/notify-sms/inbound # SMS_CODE_TTL_SEC=600 # SMS_CODE_MAX_ATTEMPTS=5 # SMS_ACTION_JWT_MAX_AGE_SEC=300 # SMS_MAX_DIDS_PER_PHONE=5 # SMS_ALERT_SEARCH_INTERVAL_MS=300000 # Requires the SmsNotificationAction claim on every /notify-sms Bearer JWT. # Setting this false removes the action authorization stage. # SMS_REQUIRE_ACTION_CLAIM=true # Returns the plaintext verification code in the POST /notify-sms/phone response. # Honored only when NODE_ENV=test-local, which is checked first. Never in production. # SMS_DEV_ECHO_CODE=false # The only DIDs this instance may text, comma-separated. Unset means no # restriction, which is the production setting. Set but empty blocks everyone. # Intended for a test server that holds live Twilio credentials: without it, a # production database restored into staging texts every verified user daily. # SMS_ALLOWED_RECIPIENT_DIDS=did:ethr:0xabc,did:ethr:0xdef # Numbers this service must never text, comma-separated, on top of the # sms_blocked_numbers table that the STOP webhook writes to. Normalized before # comparison, so formatting does not defeat them. # SMS_BLOCKED_NUMBERS=+15555550123,+15555550124