# Database Configuration DATABASE_URL=postgresql+psycopg://postgres:postgres@db:5432/chattermate # CORS Configuration add backend url to allow cors from frontend CORS_ORIGINS=["http://localhost:3000","http://localhost:8000"] # Firebase Configuration FIREBASE_CREDENTIALS=app/config/firebase-config.json # Widget Configuration # prod image remove :3000 port, since frontend is running on port 80 VITE_WIDGET_URL=http://localhost:8000 FRONTEND_URL=http://localhost:3000 # Public URL of THIS backend. Self-hosters MUST set this to their domain # (e.g. https://support.example.com) — the chat widget derives its API/WS URLs # from it, so if it stays localhost the embedded widget can't reach the backend. BACKEND_URL=http://localhost:8000 # Public help center URL style: # path -> {BACKEND_URL}/help/{slug}, served same-origin (no DNS/TLS/proxy). Default, best for self-host. # subdomain -> https://{slug}. (needs wildcard DNS + TLS; used by cloud). # A verified custom domain always overrides this. HELP_CENTER_PUBLIC_MODE=path # JWT Configuration # These sign your auth and conversation tokens - anyone who knows them can forge # tokens for any user, so the placeholders below must be replaced. Outside # ENVIRONMENT=development the app refuses to start while they are still in place. # Generate each (64 hex characters) with: # openssl rand -hex 32 JWT_SECRET_KEY=your_jwt_secret_key_here JWT_ALGORITHM=HS256 CONVERSATION_SECRET_KEY=your_conversation_secret_key_here # Encryption and Redis # REQUIRED outside development: encrypts API keys, provider/OAuth credentials, chat # messages, session summaries and agent memory at rest. Losing or changing it makes # existing data unreadable, so back it up separately from the database. # # The value is a Fernet key that has been base64-encoded a second time: a # 60-character string ending in '='. Generate one with either of: # python -c "import base64;from cryptography.fernet import Fernet;print(base64.b64encode(Fernet.generate_key()).decode())" # openssl rand -base64 32 | tr '+/' '-_' | tr -d '\n' | base64 # # Leaving the placeholder below in place means: outside development the app # refuses to start; in development it generates a throwaway key on every boot, # so anything encrypted before a restart becomes unreadable after it. ENCRYPTION_KEY=your_fernet_encryption_key_here # Escape hatch for deployments created before ENCRYPTION_KEY had to be set, whose # data is encrypted under the old public default. It downgrades the startup error # to a warning so those instances still boot. Anyone with a copy of the database # can read their conversations and stored credentials, so treat it as temporary. # Moving off the old key means re-encrypting what it wrote, not just swapping the # value - see the key-id rotation note at the top of app/core/encryption.py. # ALLOW_INSECURE_ENCRYPTION_KEY=false REDIS_ENABLED=true REDIS_URL=redis://localhost:6379/0 # Environment ENVIRONMENT=development # S3 Configuration S3_FILE_STORAGE=false S3_BUCKET=chattermate-uploads S3_REGION=us-east-1 # Leave both blank on EC2/ECS/EKS to use the attached IAM role — boto3 then # resolves credentials from its default chain. Set them only for static keys; # a placeholder value here is treated as a real (invalid) key. AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= # Lifetime of generated presigned URLs, in seconds. They are re-signed on every # response, so this only needs to outlive a page render. AWS rejects SigV4 # presigns above 604800 (7 days); larger values are clamped to that. S3_PRESIGN_EXPIRY_SECONDS=3600 # Jira — create an OAuth 2.0 (3LO) app at developer.atlassian.com. Unlike the # other integrations the redirect URI is configured here rather than derived # from BACKEND_URL, so it must match the callback registered on the Atlassian # app exactly (route: {API_V1_STR}/jira/callback). JIRA_CLIENT_ID=your_jira_client_id_here JIRA_CLIENT_SECRET=your_jira_client_secret_here JIRA_REDIRECT_URI=http://localhost:8000/api/v1/jira/callback SHOPIFY_API_KEY=your_shopify_key SHOPIFY_API_SECRET=your_shopify_secret SHOPIFY_API_VERSION=2025-04 # Slack channel — create an app at api.slack.com/apps. The OAuth redirect URI is # derived from BACKEND_URL, so add {BACKEND_URL}/api/v1/channels/slack/callback # to the app's Redirect URLs. Without SLACK_SIGNING_SECRET every incoming Slack # webhook is rejected with a 403, since signature checks fail closed. SLACK_CLIENT_ID=your_slack_client_id SLACK_CLIENT_SECRET=your_slack_client_secret SLACK_SIGNING_SECRET=your_slack_signing_secret # CRM lead push (HubSpot / Pipedrive) — create OAuth apps at # developers.hubspot.com and developers.pipedrive.com. Redirect URIs derive from # BACKEND_URL: add {BACKEND_URL}/api/v1/crm/hubspot/callback and # {BACKEND_URL}/api/v1/crm/pipedrive/callback to the respective apps. HUBSPOT_CLIENT_ID=your_hubspot_client_id HUBSPOT_CLIENT_SECRET=your_hubspot_client_secret PIPEDRIVE_CLIENT_ID=your_pipedrive_client_id PIPEDRIVE_CLIENT_SECRET=your_pipedrive_client_secret # Meta channels (WhatsApp Cloud API, Messenger, Instagram) — create an app at # developers.facebook.com. META_WEBHOOK_VERIFY_TOKEN is any random string you pick # and also enter in the App Dashboard webhook config. META_APP_ID=your_meta_app_id META_APP_SECRET=your_meta_app_secret META_WEBHOOK_VERIFY_TOKEN=any_random_string_you_choose META_GRAPH_VERSION=v21.0 # Only for cloud-hosted one-click onboarding; leave blank for self-hosting. # META_CONFIG_ID: WhatsApp Embedded Signup. META_MESSENGER_CONFIG_ID: Facebook # Login for Business, for connecting a Page (Messenger + Instagram DM). META_CONFIG_ID= META_MESSENGER_CONFIG_ID= # Instagram API with Instagram Login (no Facebook Page needed). These are the # Instagram app id/secret from the app's Instagram product, NOT the Meta ones. INSTAGRAM_APP_ID= INSTAGRAM_APP_SECRET= # Comma-separated emails allowed to use one-click Meta signup. Empty = everyone. # Set this while the Meta app is in App Review so the flow can be exercised in # production without offering customers a login that would fail for them. SIGNUP_ALLOWED_EMAILS= VERIFY_SSL_CERTIFICATES=true # Which addresses the AI base URL, MCP server URLs and ticket database (or its # SSH host) may point at. These are dialled by this server, so: # any -> no restriction. Default; lets a self-hosted install reach its # own network (Ollama on localhost, an internal MCP server, a # private database). # public_only -> refuse private, loopback, link-local and reserved addresses. # Use it when people you don't control can configure these # (a shared or multi-tenant deployment). Checked on the # address actually dialled, redirects included; these # connections then bypass HTTP(S)_PROXY. OUTBOUND_URL_POLICY=any # STDIO MCP connectors run a command on this server, typed by an org admin. # Keep true on your own install; set false wherever people you don't control # can add connectors (a shared or multi-tenant deployment). MCP_STDIO_ENABLED=true # Enhanced Website Knowledge Base Configuration KB_MAX_DEPTH=5 KB_MAX_LINKS=25 KB_MIN_CONTENT_LENGTH=100 KB_TIMEOUT=30 KB_MAX_RETRIES=3 KB_MAX_WORKERS=5 KB_BATCH_SIZE=5 KB_SOURCE_TIME_LIMIT_SECONDS=1800 KB_PDF_MAX_PAGES=300 # Seconds a single agent run (model + tool calls) may take before it is # cancelled and the visitor gets an error reply. Raise it if agents with many # MCP/Shopify tools hit the limit on legitimate answers. AGENT_RUN_TIMEOUT=90 # agno's own run reporting to api.agno.com. Off unless set to true here; when on, # it runs inside every agent run and counts against AGENT_RUN_TIMEOUT. # AGNO_TELEMETRY=true # AGNO_MONITOR=true # Tool calls an agent may make in one turn before it has to answer from what it # already retrieved. Hitting this is not an error — the agent answers without # further tools. Raise it if agents with many knowledge sources or MCP tools are # answering from too little context. AGENT_TOOL_CALL_LIMIT=5