Environment Variables
Complete reference for all environment variables used by the Talkr backend
Core environment variables are centralized in api/constants.py. Variables marked Required in the description must be explicitly set — the application will either fail to boot or behave insecurely without them.
Deployment Modes
Talkr supports two deployment modes, set via DEPLOYMENT_MODE:
- OSS: The default mode. Designed for self-hosted deployments using Docker Compose — the fastest way to get Talkr running. Uses local JWT authentication and MinIO for storage.
- SaaS: Intended for customised deployments outside of Docker, allowing greater flexibility in how the platform is hosted and integrated. Talkr is bring-your-own-key (BYOK) only — there is no managed/hosted AI model tier.
Document/knowledge-base ingestion and ad-hoc audio transcription call out to an internal dependency called MPS (MPS_API_URL, see below) that is not part of this deployment and is not reachable by default. Until an operator points MPS_API_URL at a real running service, those specific features will fail — everything else, including the /workflow/create AI-generation wizard (which uses TALKR_PLATFORM_LLM_API_KEY instead, see below), is unaffected and fully self-contained.
The relevant required variables for each mode are noted in the descriptions below.
Application
| Variable | Default | Description |
|---|---|---|
ENVIRONMENT | local | Runtime environment. Affects logging and behaviour. One of local, production, test |
DEPLOYMENT_MODE | oss | Deployment mode. Use oss for self-hosted |
AUTH_PROVIDER | local | Authentication provider. local (default) uses the built-in email/password flow. Set to stack to delegate to Stack Auth for social login — see Authentication for the full setup |
Database
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | N/A | Required. PostgreSQL connection string. e.g. postgresql+asyncpg://user:pass@host:5432/dbname |
REDIS_URL | N/A | Required. Redis connection string. e.g. redis://localhost:6379 |
Authentication (OSS)
| Variable | Default | Description |
|---|---|---|
OSS_JWT_SECRET | N/A | Required for OSS deployments. Secret used to sign JWT tokens. Must be set to a strong random value in production |
OSS_JWT_EXPIRY_HOURS | 720 | JWT token lifetime in hours (default: 30 days) |
ENABLE_SIGNUP | true | Set to false to disable public signup on invite-only installs — POST /api/v1/auth/signup returns 403 and the login page hides the Sign up link |
Never use the placeholder OSS_JWT_SECRET in a production deployment. Generate a strong random secret and store it securely.
Authentication (Stack Auth)
Set these when AUTH_PROVIDER=stack to delegate sign-in to Stack Auth for social login. The project id and publishable client key are public and are served to the browser at runtime via /api/v1/health; the secret server key stays server-side. See Authentication for the full walkthrough.
| Variable | Default | Description |
|---|---|---|
STACK_AUTH_PROJECT_ID | null | Required for stack. Stack project ID (public) |
STACK_PUBLISHABLE_CLIENT_KEY | null | Required for stack. Stack publishable client key (public) |
STACK_SECRET_SERVER_KEY | null | Required for stack. Stack secret server key — server-side only, also set on the ui service. Keep secret |
STACK_AUTH_API_URL | null | Required for stack. Stack REST API base URL (e.g. https://api.stack-auth.com) |
URLs
| Variable | Default | Description |
|---|---|---|
PUBLIC_BASE_URL | null | Canonical public origin for the deployment (scheme + host, e.g. https://203-0-113-10.sslip.io). For a standard single-host install this is the only endpoint value you set — BACKEND_API_ENDPOINT and MINIO_PUBLIC_ENDPOINT derive from it |
PUBLIC_HOST | null | Public host without scheme (e.g. 203-0-113-10.sslip.io); TURN_HOST derives from it |
BACKEND_API_ENDPOINT | PUBLIC_BASE_URL, else http://localhost:8000 | Public URL the backend builds webhook / callback / embed links from. Set explicitly only to override the value derived from PUBLIC_BASE_URL |
UI_APP_URL | http://localhost:3010 | URL of the frontend application |
MPS_API_URL | https://services.talkr.app (not a real host — see warning above) | URL of an internal document-processing dependency (MPS). Override it only if you are running your own MPS-compatible service; the knowledge-base upload pipeline requires it, everything else does not |
TALKR_MPS_SECRET_KEY | null | Secret key for authenticating with MPS, only relevant if you've pointed MPS_API_URL at a real service |
CORS_ALLOWED_ORIGINS | null | Required for non-OSS deployments. Comma-separated list of origins allowed to make credentialed cross-origin requests (e.g. https://app.example.com,https://admin.example.com). Ignored in OSS mode, which serves a permissive same-origin policy without credentials |
AI Workflow Generation
Powers the "Use Agent Builder" wizard on /workflow/create — a Talkr-owned LLM key, entirely separate from any organization's BYOK model configuration, so the feature works before an organization has configured anything.
| Variable | Default | Description |
|---|---|---|
TALKR_PLATFORM_LLM_API_KEY | null | API key for the platform-owned LLM used to generate starter workflows. Unset: the wizard returns a clear 503 and the UI falls back to Blank Canvas |
TALKR_PLATFORM_LLM_PROVIDER | google | Provider for workflow generation. Any provider TALKR_PLATFORM_LLM_API_KEY is valid for |
TALKR_PLATFORM_LLM_MODEL | gemini-3.5-flash | Model for workflow generation |
Generations are capped at 10 per organization per day (fixed, not currently configurable) since this key is shared and Talkr-paid rather than per-organization.
Trial-credit managed tier
Powers the free trial credits every new organization gets on signup (see Billing) — Talkr-owned STT/TTS keys, entirely separate from any organization's BYOK model configuration, used only as a fallback for a service the organization hasn't configured itself, metered against that organization's credit balance. The LLM side of this reuses TALKR_PLATFORM_LLM_API_KEY/_PROVIDER/_MODEL above.
| Variable | Default | Description |
|---|---|---|
TALKR_PLATFORM_STT_API_KEY | null | Deepgram API key used for trial-managed speech-to-text. Unset: trial calls needing STT aren't authorized (organizations stay BYOK-only for STT) |
TALKR_PLATFORM_STT_PROVIDER | deepgram | Provider for trial-managed STT |
TALKR_PLATFORM_STT_MODEL | nova-3-general | Model for trial-managed STT |
TALKR_PLATFORM_TTS_API_KEY | null | Deepgram API key used for trial-managed text-to-speech. Unset: trial calls needing TTS aren't authorized |
TALKR_PLATFORM_TTS_PROVIDER | deepgram | Provider for trial-managed TTS |
TALKR_PLATFORM_TTS_VOICE | aura-2-helena-en | Voice for trial-managed TTS |
TRIAL_MAX_CALL_DURATION_SECONDS | 300 | Hard ceiling on a trial-managed call's duration, regardless of the workflow's own configured max — bounds worst-case credit overrun on a single call |
Every new organization gets a one-time credit grant (TRIAL_CREDITS_INITIAL_GRANT in api/constants.py); once it's spent, calls needing a trial-managed service are rejected until the organization buys more credits or configures its own keys for that service.
Storage
Talkr uses MinIO by default, which is bundled with the self-hosted deployment and requires no external setup. Set ENABLE_AWS_S3=true to switch to AWS S3 — typically used for cloud or managed deployments where S3 is already part of the infrastructure.
MinIO (OSS default)
| Variable | Default | Description |
|---|---|---|
MINIO_ENDPOINT | localhost:9000 | MinIO server host and port |
MINIO_PUBLIC_ENDPOINT | PUBLIC_BASE_URL, else http://localhost:9000 | Publicly accessible MinIO URL for download links. Derives from PUBLIC_BASE_URL; set explicitly only for a separate object-storage origin |
MINIO_ACCESS_KEY | N/A | Required for OSS deployments. MinIO access key. Must be set to a secure value in production |
MINIO_SECRET_KEY | N/A | Required for OSS deployments. MinIO secret key. Must be set to a secure value in production |
MINIO_BUCKET | voice-audio | Bucket name for audio files |
MINIO_SECURE | false | Use HTTPS for MinIO connections |
AWS S3 (alternative)
| Variable | Default | Description |
|---|---|---|
ENABLE_AWS_S3 | false | Set to true to use AWS S3 instead of MinIO |
S3_BUCKET | null | S3 bucket name |
S3_REGION | us-east-1 | AWS region |
S3_ENDPOINT_URL | null | Custom S3 endpoint for S3-compatible servers (e.g. https://s3.example.com). Leave unset for AWS. |
S3_SIGNATURE_VERSION | null | Signing version. Unset uses botocore's default; set s3v4 for servers that require SigV4. |
S3_ADDRESSING_STYLE | null | auto (default), path, or virtual. Many S3-compatible servers and TLS setups require path. |
Credentials come from the standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY environment variables.
S3-compatible servers (MinIO, rustfs, Ceph, ...)
The S3 backend can target any S3-compatible server, not just AWS. Prefer it over the MinIO backend when you need presigned URLs against a private bucket: the MinIO backend returns plain unsigned object URLs and relies on the bucket being anonymously public-readable, whereas the S3 backend issues real presigned URLs so the bucket can stay private.
To use it, set ENABLE_AWS_S3=true and point it at your server with the S3_* overrides above. For example, against rustfs:
ENABLE_AWS_S3=true
S3_BUCKET=voice-audio
S3_REGION=us-east-1
S3_ENDPOINT_URL=https://s3.example.com
S3_SIGNATURE_VERSION=s3v4 # rustfs rejects SigV2 with SignatureDoesNotMatch
S3_ADDRESSING_STYLE=path # rustfs and most non-AWS TLS certs require path-style
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...Presigned URLs point at S3_ENDPOINT_URL, so that host must be reachable from the browser. Because browsers fetch transcripts cross-origin, the bucket also needs a CORS rule allowing your app's origin for GET/HEAD — configure this on the storage server (e.g. via PutBucketCors), not in Talkr.
WebRTC
| Variable | Default | Description |
|---|---|---|
ENABLE_COTURN | false | Whether this deployment runs a TURN server. Reported to browsers as turn_enabled on /api/v1/health and in the embed widget config; when false clients skip the TURN credential request and connect over STUN, and the server returns 503 from the credential endpoints. Set to true wherever coturn is running — the setup scripts and Helm chart do this for you |
TURN_HOST | PUBLIC_HOST, else localhost | TURN server hostname for WebRTC NAT traversal. Derives from PUBLIC_HOST; set explicitly only when TURN runs on a separate host |
TURN_PORT | 3478 | TURN server port |
TURN_TLS_PORT | 5349 | TURN server TLS port |
TURN_SECRET | null | Required for WebRTC. Shared secret for TURN credential generation |
TURN_CREDENTIAL_TTL | 86400 | TURN credential validity in seconds (default: 24h) |
FORCE_TURN_RELAY | false | Diagnostic flag. When true, restricts ICE to relay-only candidates on both server (SDP filter) and browser (iceTransportPolicy: 'relay'). Use to verify TURN connectivity end-to-end — calls fail cleanly if TURN is misconfigured instead of silently falling back to a direct path. |
Tracing (Langfuse)
| Variable | Default | Description |
|---|---|---|
LANGFUSE_HOST | null | Langfuse server URL |
LANGFUSE_PUBLIC_KEY | null | Langfuse public key |
LANGFUSE_SECRET_KEY | null | Langfuse secret key |
Tracing activates automatically as soon as credentials are available — either via these environment variables (applied to all organizations) or per-organization in the UI under Platform Settings. If neither is set, spans are dropped silently. See the Tracing guide for setup instructions.
Telephony
Carriers dial the media WebSocket back at /api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}. Those ids travel in a caller-visible URL, so on their own they are a guessable capability. Setting a secret makes Talkr sign that URL with an HMAC and verify the signature when the socket opens.
The signature travels as a trailing path segment — /api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}/{token} — because carriers do not reliably forward query strings. Twilio documents that its <Stream> url "does not support query string parameters" and drops them outright. Asterisk ARI is the exception: it connects to /api/v1/telephony/ws/ari and passes token as a query parameter alongside its other routing values, which works because Asterisk builds that URL itself.
| Variable | Default | Description |
|---|---|---|
TELEPHONY_WS_TOKEN_SECRET | null | Secret used to sign the media WebSocket URL. Unset leaves URLs unchanged and the check disabled |
TELEPHONY_WS_TOKEN_ENFORCE | false | Reject connections whose token is missing or invalid (WebSocket close 4401) |
Roll it out in two steps so no call is dropped:
- Set
TELEPHONY_WS_TOKEN_SECRETon every process that places or receives calls — theapiservice and, if you run Asterisk, theari-manager. They must share the same value: one mints the token, the other verifies it. Calls keep connecting either way; anything unverifiable is logged asUNVERIFIED media socket. - Once those warnings stop, set
TELEPHONY_WS_TOKEN_ENFORCE=trueto start rejecting them.
Setting TELEPHONY_WS_TOKEN_ENFORCE without a secret does nothing at all — the check is skipped entirely rather than rejecting every connection.
The signed URL is a bearer credential, and it is not hidden: the token appears in full in the api and nginx access logs, and in carrier-side request logs (Twilio's debugger, Telnyx's request inspector). Anyone who can read those logs can open the media socket for a run that is still in initialized. Treat log access as socket access.
Monitoring
| Variable | Default | Description |
|---|---|---|
SENTRY_DSN | null | Sentry DSN for error tracking |
ENABLE_TELEMETRY | false | Enable anonymous telemetry collection |
Logging
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | DEBUG | Log level: DEBUG, INFO, WARNING, ERROR |
LOG_FILE_PATH | null | Write logs to this file path (in addition to stdout) |
LOG_ROTATION_SIZE | 100 MB | Rotate log file when it reaches this size |
LOG_RETENTION | 7 days | How long to keep rotated log files |
LOG_COMPRESSION | gz | Compression format for rotated logs |
SERIALIZE_LOG_OUTPUT | false | Output logs as JSON (useful for log aggregation) |
Campaigns
Controls concurrency for Campaigns, Talkr's bulk outbound calling feature.
| Variable | Default | Description |
|---|---|---|
DEFAULT_ORG_CONCURRENCY_LIMIT | 10 | Maximum concurrent active calls per organization (values below 1 are clamped to 1) |
Further Customisation
The variables documented here cover the standard configuration surface. For advanced customisation — such as integrating additional services or tuning internal behaviour — consult the relevant module alongside api/constants.py to understand how each variable is consumed.