Last updated July 13, 2026
VoiceBlender bridges SIP and WebRTC voice calls with multi-party audio mixing, real-time speech-to-text, text-to-speech, AI agent integration, recording, and webhook-based event delivery.
Configuration
| Variable | Default | Description |
|---|---|---|
INSTANCE_ID | (auto-generated UUID) | Instance identifier included in all API responses and webhook events |
HTTP_ADDR | :8080 | REST API listen address |
ALLOWED_IPS | (empty = allow all) | Comma-separated allowlist of IPs and CIDR ranges (IPv4 and IPv6) gating every HTTP endpoint, including /v1/vsi, /v1/legs/websocket, /v1/legs/moq, /metrics, and pprof. Bare addresses become /32 (v4) or /128 (v6); malformed entries fail server startup. Only X-Forwarded-For is consulted as a proxy header (see TRUST_PROXY_HEADERS). |
TRUST_PROXY_HEADERS | false | When true, the client IP used for the ALLOWED_IPS check is taken from the leftmost X-Forwarded-For entry (falling back to the socket peer if absent). Enable only behind a trusted reverse proxy that overwrites the header — otherwise it is client-spoofable. |
SIP_BIND_IP | 127.0.0.1 | IPv4 address advertised in SDP, Contact, and Via headers (and used as the listen address when SIP_LISTEN_IP is empty) |
SIP_LISTEN_IP | (same as SIP_BIND_IP) | UDP socket bind IP. Accepts 127.0.0.1, 0.0.0.0, ::, or any literal v4/v6 address |
SIP_BIND_IPV6 | (empty = v4-only) | IPv6 address advertised in SDP/Contact/Via for IPv6 calls. Set this for IPv6-only or dual-stack deployments |
SIP_LISTEN_IPV6 | (same as SIP_BIND_IPV6) | Optional separate IPv6 socket bind address (used when running with both 0.0.0.0 and a specific v6 literal) |
SIP_EXTERNAL_IP | — | Public IPv4 address for NAT/Docker deployments. When set, used in SIP Contact headers and SDP media (c=) lines instead of the bind IP. IPv6 has no equivalent — set SIP_BIND_IPV6 to the address you want advertised. |
SIP_PORT | 5060 | SIP listen port |
SIP_TLS_PORT | (disabled) | SIP-over-TLS listen port (typically 5061). When set, SIP_TLS_CERT and SIP_TLS_KEY must also be provided. Required for WhatsApp Business Calling integration. |
SIP_TLS_CERT | — | Path to PEM-encoded TLS certificate (e.g. fullchain.pem). Meta rejects self-signed certs — use a CA-signed cert matching a public FQDN. |
SIP_TLS_KEY | — | Path to PEM-encoded TLS private key (e.g. privkey.pem). |
SIP_DEBUG | false | When true, log the full RFC 3261 wire form of every inbound and outbound SIP request and response. Very verbose — use only for troubleshooting. |
SIP_DOMAIN | (falls back to advertised IP) | FQDN advertised in From, Contact and Via on all outbound SIP signalling (classic trunks and WhatsApp). Should match the SAN on SIP_TLS_CERT and any allowlist your carrier or Meta keeps. |
SIP_HOST | voiceblender | SIP User-Agent name |
SIP_CODECS | PCMU,PCMA | Comma-separated, preference-ordered list of codecs the SIP engine offers on outbound INVITEs and accepts on inbound INVITEs. Recognized names (case-insensitive): PCMU, PCMA, G722, opus, AMR-WB, AMR-NB (bare token AMR resolves to AMR-NB per RFC 4867 §8.1). Unknown names and duplicates are dropped silently. |
SIP_AUTO_RINGING | false | When true, the server sends 180 Ringing automatically after 100 Trying. Default sends only 100 Trying; the API caller drives ringing via /ring, /early-media, or /answer. |
SIP_USE_SOURCE_SOCKET | false | When true, route SIP responses and in-dialog requests (BYE, re-INVITE, UPDATE, INFO, NOTIFY, REFER) back to the request's source UDP socket instead of the peer's Contact / Via sent-by. Enable when peers advertise unroutable addresses (e.g. private IPs in Contact from behind NAT). |
SIP_REGISTRATION_DEFAULT_EXPIRES_SECONDS | 3600 | Expiry used when an inbound REGISTER carries no Expires value. |
SIP_REGISTRATION_MAX_EXPIRES_SECONDS | 7200 | Upper clamp on the granted REGISTER expiry. Requests above this value are honored at this maximum. |
SIP_REGISTRATION_SWEEP_INTERVAL_MS | 1000 | Sweeper period (ms) for evicting expired AOR bindings. |
SIP_REGISTRATION_ALLOW_MULTIPLE_CONTACTS | true | When true, the same AOR may be bound from multiple Contacts simultaneously (and POST /v1/legs parallel-forks to every bound contact). When false, each REGISTER replaces any prior Contacts for the AOR. |
ICE_SERVERS | stun:stun.l.google.com:19302 | STUN/TURN URLs for WebRTC ICE, comma-separated |
WEBRTC_EXTERNAL_IPS | (empty) | Comma-separated public IPs advertised as host ICE candidates (pion SetNAT1To1IPs). Required when VB runs behind NAT/Docker so peers behind firewalls can reach it; supports IPv4 and IPv6 literals. The literal value "auto" triggers STUN-based public-IP discovery at startup using the configured ICE_SERVERS; failure is non-fatal. |
RTP_PORT_MIN | 10000 | Minimum UDP port for RTP/RTCP media |
RTP_PORT_MAX | 20000 | Maximum UDP port for RTP/RTCP media |
DEFAULT_SAMPLE_RATE | 16000 | Default mixer sample rate (Hz) for new rooms when sample_rate is not specified. Allowed: 8000, 16000, 48000. |
SPEECH_DETECTION_ENABLED | false | Emit speaking.started / speaking.stopped events for every connected leg by default. Per-call speech_detection on POST /v1/legs or POST /v1/legs/{id}/answer overrides this. |
VSI_EVENT_BUFFER_SIZE | 256 | Per-client buffer (in events) on the /v1/vsi WebSocket. When the client falls behind, new events are dropped and the next delivered event carries an events_dropped notification. Clamped to [16, 1000000]. Memory: ~1 KB × buffer per connection at the default. |
AMRWB_MODE | 2 | AMR-WB (G.722.2) encoder speech-mode ceiling 0..8: 0=6.60, 1=8.85, 2=12.65, 3=14.25, 4=15.85, 5=18.25, 6=19.85, 7=23.05, 8=23.85 kbit/s. The actual transmit mode is this ceiling clamped to the peer's negotiated mode-set. Default 2 matches GSMA IR.92 / VoLTE. |
AMRWB_OCTET_ALIGNED | true | Offer octet-aligned AMR-WB framing (RFC 4867) in outbound SDP. When false, offers bandwidth-efficient framing. On answers, VoiceBlender always echoes the framing the peer negotiated. |
AMRNB_MODE | 7 | AMR-NB (RFC 4867) encoder speech-mode ceiling 0..7: 0=4.75, 1=5.15, 2=5.90, 3=6.70, 4=7.40, 5=7.95, 6=10.2, 7=12.2 kbit/s. The actual transmit mode is this ceiling clamped to the peer's negotiated mode-set. Default 7 is GSM-EFR-equivalent 12.2 kbit/s. |
AMRNB_OCTET_ALIGNED | true | Offer octet-aligned AMR-NB framing (RFC 4867) in outbound SDP. When false, offers bandwidth-efficient framing. On answers, VoiceBlender always echoes the framing the peer negotiated. |
RECORDING_DIR | /tmp/recordings | Local directory for recording output files |
LOG_LEVEL | info | Log verbosity: debug, info, warn, error |
WEBHOOK_URL | — | Global webhook URL for event delivery (fallback when no per-leg or per-room webhook is set) |
WEBHOOK_SECRET | — | HMAC-SHA256 signing secret for the global webhook |
ELEVENLABS_API_KEY | — | API key for ElevenLabs TTS, STT, and Agent provider |
VAPI_API_KEY | — | API key for VAPI Agent provider |
DEEPGRAM_API_KEY | — | API key for Deepgram STT and TTS |
AZURE_SPEECH_KEY | — | Subscription key for Azure Cognitive Speech Services (TTS and STT) |
AZURE_SPEECH_REGION | eastus | Azure region for Speech Services (e.g. eastus, westeurope) |
S3_BUCKET | — | S3 bucket name for recording uploads |
S3_REGION | us-east-1 | AWS region for S3 |
S3_ENDPOINT | — | Custom S3-compatible endpoint (e.g. MinIO) |
S3_PREFIX | — | Key prefix applied to all S3 objects |
AWS_ACCESS_KEY_ID | — | [SDK-resolved, not read by VoiceBlender] AWS access key for S3 uploads and AWS Polly TTS. Consumed by the AWS SDK default credential chain alongside AWS_SECRET_ACCESS_KEY and the optional AWS_SESSION_TOKEN. |
AWS_SECRET_ACCESS_KEY | — | [SDK-resolved, not read by VoiceBlender] AWS secret key paired with AWS_ACCESS_KEY_ID. |
AWS_SESSION_TOKEN | — | [SDK-resolved, not read by VoiceBlender] Optional temporary-credential session token (STS / SSO) used together with AWS_ACCESS_KEY_ID/SECRET. |
AWS_PROFILE | — | [SDK-resolved, not read by VoiceBlender] Profile name in ~/.aws/credentials to use instead of static AWS_* env vars. |
AWS_REGION | — | [SDK-resolved, not read by VoiceBlender] AWS region used by S3 and Polly when S3_REGION is empty. |
GOOGLE_APPLICATION_CREDENTIALS | — | [SDK-resolved, not read by VoiceBlender] Path to a Google Cloud service-account JSON file used by Google Cloud TTS when no per-request api_key is supplied. Consumed by Google's Application Default Credentials chain. |
TTS_CACHE_ENABLED | false | Enable disk-backed TTS audio cache; cached audio persists across restarts |
TTS_CACHE_DIR | /tmp/tts_cache | Directory for cached TTS audio files (used when TTS_CACHE_ENABLED=true) |
TTS_CACHE_INCLUDE_API_KEY | false | Include API key in TTS cache key; set true if different keys map to different voice clones |
SIP_JITTER_BUFFER_MS | 0 | SIP ingress jitter buffer target delay in ms (0 = disabled passthrough). Applies to every SIP leg. |
SIP_JITTER_BUFFER_MAX_MS | 300 | Maximum depth of the SIP ingress jitter buffer in ms. Frames beyond this are dropped oldest-first to catch up after a stall. |
SIP_REFER_AUTO_DIAL | false | When true, accept incoming SIP REFER requests and automatically originate the transferred call. Default-deny: stays off unless the SIP edge is locked down (IP allow-lists, digest auth) because auto-dialing arbitrary Refer-To URIs is a classic toll-fraud vector. Outbound transfers initiated via the REST API are unaffected by this flag. |
MOQ_ENABLED | false | Enable the experimental MoQ (Media over QUIC) inbound leg endpoint at CONNECT /v1/legs/moq over WebTransport/HTTP/3. PoC quality, tracks IETF draft-11. When enabled, both MOQ_TLS_CERT_FILE and MOQ_TLS_KEY_FILE must be set. |
MOQ_LISTEN_ADDR | :8443 | UDP address for the HTTP/3 listener that backs the MoQ leg. Independent of HTTP_ADDR — TCP/:8080 and UDP/:8443 can run side-by-side. |
MOQ_TLS_CERT_FILE | — | Path to the TLS certificate used by the HTTP/3 listener. Required when MOQ_ENABLED=true. |
MOQ_TLS_KEY_FILE | — | Path to the TLS private key used by the HTTP/3 listener. Required when MOQ_ENABLED=true. |
MOQ_OPUS_BITRATE | 24000 | Target bitrate (bps) for the Opus encoder feeding the MoQ leg's mix track. Must be in 6000..510000. |
LIVEKIT_ENABLED | false | Enable the livekit_room leg type at POST /v1/legs (type=livekit_room). Lets VoiceBlender join a LiveKit room as a participant and bridge audio between SIP and LiveKit. Speaks the LiveKit signaling protocol directly via livekit/protocol protobufs over the existing pion stack — no LiveKit SDK is used. |
LIVEKIT_URL | — | Default LiveKit server endpoint (wss://...). Required when LIVEKIT_ENABLED=true unless every request supplies livekit.url. Overridable per-request. |
LIVEKIT_OPUS_BITRATE | 24000 | Target bitrate (bps) for the Opus encoder publishing audio into LiveKit. Must be in 6000..510000. Overridable per-request via livekit.opus_bitrate. |
LIVEKIT_TOKEN_SIGNING_ENABLED | false | Opt-in: when true, callers may omit livekit.token and instead pass {room,identity,permissions}; VoiceBlender mints the JWT itself. Security caveat: enabling this stores the LiveKit API secret (a high-privilege credential) in VoiceBlender. Keep off in multi-tenant deployments. |
LIVEKIT_API_KEY | — | LiveKit API key used to sign minted JWTs. Required only when LIVEKIT_TOKEN_SIGNING_ENABLED=true. |
LIVEKIT_API_SECRET | — | LiveKit API secret used to sign minted JWTs. Required only when LIVEKIT_TOKEN_SIGNING_ENABLED=true. Treat as a high-value secret; redact in logs. |
LIVEKIT_DEFAULT_TOKEN_TTL | 6h | Default TTL applied to minted JWTs when the request omits livekit.token_ttl. Go duration string. LiveKit recommends ≤ 6 hours. |