# Whatomate Configuration # Copy this to config.toml and update values # # For Docker: use "db" and "redis" as hostnames # For local dev: use "localhost" [app] name = "Whatomate" environment = "development" # development, staging, production debug = true encryption_key = "" # AES-256 key for encrypting secrets at rest (32+ chars, required in production) [server] host = "0.0.0.0" port = 8080 read_timeout = 30 write_timeout = 30 base_path = "" # Set to "/subpath" if behind nginx proxy pass allowed_origins = "" # Comma-separated CORS origins (e.g., "https://app.example.com,https://admin.example.com"). Empty = allow all (dev only). [database] host = "db" # Use "localhost" for local development port = 5432 user = "whatomate" password = "whatomate" name = "whatomate" ssl_mode = "disable" max_open_conns = 25 max_idle_conns = 5 conn_max_lifetime = 300 [redis] host = "redis" # Use "localhost" for local development port = 6379 username = "" # Redis ACL username (Redis 6+). Leave empty to use the default user. password = "" db = 0 tls = false # Set to true for TLS connections (e.g. Upstash, Redis Cloud) [jwt] secret = "your-super-secret-jwt-key-change-in-production" # Must be 32+ chars in production access_expiry_mins = 15 refresh_expiry_days = 1 [storage] type = "local" # local, s3 local_path = "./uploads" s3_bucket = "" s3_region = "" # Leave s3_key/s3_secret empty to use the AWS default credential chain # (env vars, shared config, EKS IRSA, ECS task role, EC2 instance profile). s3_key = "" s3_secret = "" [whatsapp] webhook_verify_token = "random-string-change-this" api_version = "v24.0" base_url = "https://graph.facebook.com" app_id = "" # Meta App ID for Embedded Signup app_secret = "" # Meta App Secret config_id = "" # WhatsApp Config ID for frontend login # Auth cookie settings (tokens are stored in httpOnly cookies) [cookie] domain = "" # Cookie domain (e.g., ".example.com"). Empty = current host only. secure = false # Set Secure flag on cookies. Auto-set true when environment=production. # Rate limiting for auth endpoints (uses Redis fixed-window counters) [rate_limit] enabled = false # Set to true to enable rate limiting login_max_attempts = 10 # Max login attempts per IP per window register_max_attempts = 10 # Max register attempts per IP per window refresh_max_attempts = 30 # Max token refresh attempts per IP per window sso_max_attempts = 10 # Max SSO init/callback attempts per IP per window window_seconds = 60 # Time window in seconds trust_proxy = false # Trust X-Forwarded-For / X-Real-IP headers (set true behind reverse proxy) api_max_requests = 200 # Max requests per IP per window for all /api/ routes (0 = 200) api_window_seconds = 60 # Time window for global API rate limit (0 = 60) # Text-to-Speech for IVR greetings (optional, requires piper + opusenc installed) # Download piper: https://github.com/rhasspy/piper/releases (standalone binary) # Download voice models: https://huggingface.co/rhasspy/piper-voices # Install opusenc: apt install opus-tools (Debian/Ubuntu) / dnf install opus-tools (Fedora) [tts] # piper_binary = "/usr/local/bin/piper" # piper_model = "/opt/piper/models/en_US-lessac-medium.onnx" # opusenc_binary = "opusenc" # defaults to finding in PATH # WhatsApp Calling / WebRTC [calling] max_call_duration = 300 # Max call duration in seconds audio_dir = "./audio" # Directory for IVR audio files # hold_music_file = "hold_music.opus" # ringback_file = "ringback.opus" transfer_timeout_secs = 120 # How long to wait for agent to accept transfer per_agent_timeout_secs = 15 # How long each agent in a team rotation is rung sticky_ring_secs = 30 # How long a click-to-call button rings the agent who sent it # (those calls never fall back to the team) recording_enabled = true # Record calls to S3 (requires [storage] s3 config) udp_port_min = 10000 # WebRTC UDP port range start udp_port_max = 10100 # WebRTC UDP port range end # public_ip = "1.2.3.4" # Public IP for NAT mapping (required on AWS/cloud) # relay_only = true # Force all media through TURN relay (no direct UDP needed) # ICE servers for WebRTC NAT traversal # Configure STUN, TURN, or both. Only what you configure is used. # - STUN only: works when direct UDP is not blocked by firewall # - TURN only: relays all traffic, works behind any firewall # - Both: tries direct (STUN) first, falls back to TURN # Option A: STUN only (simple, no relay server needed) # [[calling.ice_servers]] # urls = ["stun:stun.l.google.com:19302"] # Option B: TURN only (use when firewall blocks direct UDP) # [[calling.ice_servers]] # urls = ["turn:your-turn-server.com:3478"] # username = "user" # credential = "password" # Option C: Both (recommended — direct when possible, relay as fallback) # [[calling.ice_servers]] # urls = ["stun:stun.l.google.com:19302"] # [[calling.ice_servers]] # urls = ["turn:your-turn-server.com:3478"] # username = "user" # credential = "password" # Option D: TURN with a shared secret (coturn "use-auth-secret" / TURN REST API). # When `secret` is set it takes priority over username/credential: short-lived # credentials are generated per request (username = expiry timestamp, credential # = base64(HMAC-SHA1(secret, username))). Match `secret` to coturn's # `static-auth-secret`. `credential_ttl` (seconds) sets lifetime (default 86400). # [[calling.ice_servers]] # urls = ["turn:your-turn-server.com:3478"] # secret = "your-coturn-static-auth-secret" # credential_ttl = 86400 # Default admin credentials (only used during initial setup when no users exist) [default_admin] email = "admin@admin.com" password = "admin" full_name = "Admin"