Talkr AI
Developer Guides

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.

The relevant required variables for each mode are noted in the descriptions below.


Application

VariableDefaultDescription
ENVIRONMENTlocalRuntime environment. Affects logging and behaviour. One of local, production, test
DEPLOYMENT_MODEossDeployment mode. Use oss for self-hosted
AUTH_PROVIDERlocalAuthentication 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
CORS_ALLOWED_ORIGINS(empty)Comma-separated list of additional origins allowed to make cross-origin requests to the API, e.g. https://app.example.com,https://embed.example.com

Database

VariableDefaultDescription
DATABASE_URLN/ARequired. PostgreSQL connection string. e.g. postgresql+asyncpg://user:pass@host:5432/dbname
REDIS_URLN/ARequired. Redis connection string. e.g. redis://localhost:6379
CREDENTIAL_ENCRYPTION_KEYN/ARequired. Fernet key used to encrypt BYOK provider keys, connector credentials, and telephony credentials before they reach the database — see Security & Compliance. Treat with the same care as a database root password; no key-rotation tooling exists today, so keep it out of version control

Authentication (OSS)

VariableDefaultDescription
OSS_JWT_SECRETN/ARequired for OSS deployments. Secret used to sign JWT tokens. Must be set to a strong random value in production
OSS_JWT_EXPIRY_HOURS720JWT token lifetime in hours (default: 30 days)
ENABLE_SIGNUPtrueSet to false to disable public signup on invite-only installs — POST /api/v1/auth/signup returns 403, /auth/signup redirects to /request-access, and the login page links there instead of "Sign up"

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.

VariableDefaultDescription
STACK_AUTH_PROJECT_IDnullRequired for stack. Stack project ID (public)
STACK_PUBLISHABLE_CLIENT_KEYnullRequired for stack. Stack publishable client key (public)
STACK_SECRET_SERVER_KEYnullRequired for stack. Stack secret server key — server-side only, also set on the ui service. Keep secret
STACK_AUTH_API_URLnullRequired for stack. Stack REST API base URL (e.g. https://api.stack-auth.com)

URLs

VariableDefaultDescription
PUBLIC_BASE_URLnullCanonical 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_HOSTnullPublic host without scheme (e.g. 203-0-113-10.sslip.io); TURN_HOST derives from it
BACKEND_API_ENDPOINTPUBLIC_BASE_URL, else http://localhost:8000Public URL the backend builds webhook / callback / embed links from. Set explicitly only to override the value derived from PUBLIC_BASE_URL
UI_APP_URLhttp://localhost:3010URL of the frontend application
CORS_ALLOWED_ORIGINSnullRequired 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.

VariableDefaultDescription
TALKR_PLATFORM_LLM_API_KEYnullAPI 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_PROVIDERgoogleProvider for workflow generation and the trial-managed LLM. Only google is wired for the trial tier — any other value makes it decline to provide an LLM (logged once as an error) rather than misuse the key
TALKR_PLATFORM_LLM_MODELgemini-3.5-flashModel 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.

VariableDefaultDescription
TALKR_PLATFORM_STT_API_KEYnullDeepgram 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_PROVIDERdeepgramProvider for trial-managed STT. Only deepgram is wired — any other value makes the trial tier decline to provide STT (logged once as an error) rather than misuse the key
TALKR_PLATFORM_STT_MODELflux-general-multiModel for trial-managed STT — Deepgram's multilingual/code-switching model, chosen over nova-3-general for more reliable recognition on mixed-language calls
TALKR_PLATFORM_TTS_API_KEYnullDeepgram API key used for trial-managed text-to-speech. Unset: trial calls needing TTS aren't authorized
TALKR_PLATFORM_TTS_PROVIDERdeepgramProvider for trial-managed TTS. Only deepgram is wired — any other value makes the trial tier decline to provide TTS (logged once as an error) rather than misuse the key
TALKR_PLATFORM_TTS_VOICEaura-2-helena-enVoice for trial-managed TTS
TRIAL_MAX_CALL_DURATION_SECONDS300Hard 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)

VariableDefaultDescription
MINIO_ENDPOINTlocalhost:9000MinIO server host and port
MINIO_PUBLIC_ENDPOINTPUBLIC_BASE_URL, else http://localhost:9000Publicly accessible MinIO URL for download links. Derives from PUBLIC_BASE_URL; set explicitly only for a separate object-storage origin
MINIO_ACCESS_KEYN/ARequired for OSS deployments. MinIO access key. Must be set to a secure value in production
MINIO_SECRET_KEYN/ARequired for OSS deployments. MinIO secret key. Must be set to a secure value in production
MINIO_BUCKETvoice-audioBucket name for audio files
MINIO_SECUREfalseUse HTTPS for MinIO connections

AWS S3 (alternative)

VariableDefaultDescription
ENABLE_AWS_S3falseSet to true to use AWS S3 instead of MinIO
S3_BUCKETnullS3 bucket name
S3_REGIONus-east-1AWS region
S3_ENDPOINT_URLnullCustom S3 endpoint for S3-compatible servers (e.g. https://s3.example.com). Leave unset for AWS.
S3_SIGNATURE_VERSIONnullSigning version. Unset uses botocore's default; set s3v4 for servers that require SigV4.
S3_ADDRESSING_STYLEnullauto (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

VariableDefaultDescription
ENABLE_COTURNfalseWhether 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_HOSTPUBLIC_HOST, else localhostTURN server hostname for WebRTC NAT traversal. Derives from PUBLIC_HOST; set explicitly only when TURN runs on a separate host
TURN_PORT3478TURN server port
TURN_TLS_PORT5349TURN server TLS port
TURN_SECRETnullRequired for WebRTC. Shared secret for TURN credential generation
TURN_CREDENTIAL_TTL86400TURN credential validity in seconds (default: 24h)
FORCE_TURN_RELAYfalseDiagnostic 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)

VariableDefaultDescription
LANGFUSE_HOSTnullLangfuse server URL
LANGFUSE_PUBLIC_KEYnullLangfuse public key
LANGFUSE_SECRET_KEYnullLangfuse 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.

VariableDefaultDescription
TELEPHONY_WS_TOKEN_SECRETnullSecret used to sign the media WebSocket URL. Unset leaves URLs unchanged and the check disabled
TELEPHONY_WS_TOKEN_ENFORCEfalseReject connections whose token is missing or invalid (WebSocket close 4401)

Roll it out in two steps so no call is dropped:

  1. Set TELEPHONY_WS_TOKEN_SECRET on every process that places or receives calls — the api service and, if you run Asterisk, the ari-manager. They must share the same value: one mints the token, the other verifies it. Calls keep connecting either way; anything unverifiable is logged as UNVERIFIED media socket.
  2. Once those warnings stop, set TELEPHONY_WS_TOKEN_ENFORCE=true to 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.


Rate Limiting

VariableDefaultDescription
API_RATE_LIMIT_ENFORCEtrueKill-switch for request-level API rate limiting. Set false to disable without a redeploy
API_RATE_LIMIT_PER_KEY_RPS10Max requests per second for traffic presenting an X-API-Key header, bucketed per key
API_RATE_LIMIT_PER_IP_RPS30Max requests per second for everything else (dashboard sessions, unauthenticated routes), bucketed per client IP

Telephony webhook callbacks (/api/v1/telephony/*) and health-check endpoints are never subject to this limit, so real calls and infra liveness checks are unaffected regardless of these values.


Monitoring

VariableDefaultDescription
SENTRY_DSNnullSentry DSN for error tracking
ENABLE_TELEMETRYfalseEnable anonymous telemetry collection
POSTHOG_API_KEYnullPostHog project API key for product-analytics event capture. Unset: PostHog events aren't sent
POSTHOG_HOSThttps://us.i.posthog.comPostHog ingestion host

Logging

VariableDefaultDescription
LOG_LEVELDEBUGLog level: DEBUG, INFO, WARNING, ERROR
LOG_FILE_PATHnullWrite logs to this file path (in addition to stdout)
LOG_ROTATION_SIZE100 MBRotate log file when it reaches this size
LOG_RETENTION7 daysHow long to keep rotated log files
LOG_COMPRESSIONgzCompression format for rotated logs
SERIALIZE_LOG_OUTPUTfalseOutput logs as JSON (useful for log aggregation)

Campaigns

Controls concurrency for Campaigns, Talkr's bulk outbound calling feature.

VariableDefaultDescription
DEFAULT_ORG_CONCURRENCY_LIMIT10Maximum concurrent active calls per organization (values below 1 are clamped to 1)

Capacity & Scaling

See Scaling for the full picture of how these interact.

VariableDefaultDescription
GLOBAL_CONCURRENT_CALL_LIMIT30Platform-wide ceiling on concurrent active call pipelines, across every organization (values below 1 are clamped to 1)
DB_POOL_SIZE20SQLAlchemy async engine base connection pool size for the shared db_client singleton — shared by every HTTP route and every in-flight call pipeline on one FastAPI worker
DB_MAX_OVERFLOW20Additional connections SQLAlchemy may open beyond DB_POOL_SIZE under load

Billing (Razorpay)

Only relevant if you've enabled paid credit top-ups via Razorpay. Unset: billing/top-up endpoints are unavailable, credits work purely as a usage meter with no purchase flow.

VariableDefaultDescription
RAZORPAY_KEY_IDnullRazorpay API key ID
RAZORPAY_KEY_SECRETnullRazorpay API key secret
RAZORPAY_WEBHOOK_SECRETnullSeparate secret used only to verify inbound Razorpay webhook signatures — not the same value as RAZORPAY_KEY_SECRET

Webhooks

Tuning for outbound webhook delivery retries.

VariableDefaultDescription
WEBHOOK_DELIVERY_MAX_ATTEMPTS5Maximum delivery attempts before giving up on a webhook event
WEBHOOK_DELIVERY_BASE_DELAY_SECONDS30Base delay before the first retry (subsequent retries back off from here)
WEBHOOK_DELIVERY_MAX_DELAY_SECONDS600Ceiling on the backoff delay between retries
WEBHOOK_DELIVERY_TIMEOUT_SECONDS30Timeout for each individual delivery attempt

Email

VariableDefaultDescription
SENDGRID_API_KEYnullSendGrid API key used for transactional email (invites, alerts, notifications). Unset: email sending is unavailable
SENDGRID_FROM_EMAILnullVerified sender address for outbound email
SALES_NOTIFICATION_EMAIL(empty, falls back to SENDGRID_FROM_EMAIL)Where request-access / sales-lead notifications are sent

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.

On this page