When a call begins, VoxCore fetches the bot’s full runtime configuration from VoxBridge. This single response carries everything the live pipeline needs: prompts, provider settings + injected API keys, tools, transfer config, variable namespaces, and post-call instructions. The same endpoint serves all four transports.
GET /api/v1/config/{bot_id}?caller_id=...&stream_id=...&connected_event={...}
X-VoxCore-Secret: {secret}
The route is get_config() in routes/config.py; the contract is assembled by build_config_for_call() in services/config_service.py.
The endpoint requires X-VoxCore-Secret. A mismatch returns 403. An unknown bot_id returns 404. A call arriving outside active hours returns 503 with detail outside_active_hours: ....

Query parameters

ParamDefaultPurpose
caller_id""Caller number, stored on the call skeleton.
stream_id""Transport stream identifier (used by WebSocket-transport CDR merge).
connected_event"{}"URL-encoded JSON of call/campaign/CRM variables. Parsed into a dict; malformed JSON falls back to {}.

connected_event

connected_event is the dynamic per-call payload. Every field becomes a call.* template variable (userrefno{{call.userrefno}}) and is stored on the call record for post-call variable access. It also seeds effective_crm (see Variable namespaces). Reserved control flags are popped from the event before variables are built:
FlagEffect
_campaign_session_idOverrides the generated session_id.
_skip_prefetchSkip the CRM pre-fetch HTTP call.
_skip_post_pushMark the call so the post-call CRM push is skipped.
_mock_crmTest-form CRM values, merged between connected_event and live pre-fetch.
_campaign_id / _campaign_call_id / _campaign_attempt / _campaign_run_numberCampaign linkage; also used to load callback context.
sip_candidate_headersRaw SIP X-headers, filtered by the bot’s sip_header_config into sip_context.

Build flow

Active-hours gating

If bot.active_hours.enabled is true, the gate runs before any expensive work (CRM pre-fetch, prompt rendering) and raises OutsideActiveHoursError (→ 503) when the call falls outside the window:
  • The bot timezone is resolved (invalid timezone falls back to UTC with a warning).
  • The current local weekday must be in active_hours.days (default: all 7 days).
  • The current local time must fall within start_timeend_time. Overnight windows (e.g. 22:0006:00) are handled when start > end.

Variable namespaces

Prompts, opening message, analysis/QC prompts, and agent-desk context are all rendered against a merged variable dict:
NamespaceSourceExample
system.*Current date/time in the bot timezonesystem.current_date, system.current_time, system.current_datetime, system.timezone
call.*Every connected_event field + filtered SIP header variables (+ callback context on callback attempts)call.userrefno, call.callerId
crm.*effective_crm = connected_event < _mock_crm < live CRM pre-fetch (later wins)crm.CUSTOMERNAME, crm.amount

Name transliteration

When a recognised name field is present (CUSTOMERNAME, name, customer_name, borrower_name, farmer_name, FIRSTNAME — first match wins), VoxBridge adds Devanagari variants for Hindi TTS via to_devanagari / to_firstname_devanagari: crm.CUSTOMERNAME_HI, crm.FIRSTNAME, crm.FIRSTNAME_HI, plus call.<field>_hi, call.<field>_firstname, call.<field>_firstname_hi.

Contract shape

build_config_for_call() returns a flat dict. Selected fields:
FieldNotes
session_idGenerated UUID unless _campaign_session_id overrides.
webhook_urlhttps://{host}/api/v1/call-results — where VoxCore posts results.
system_promptRendered prompt. For policy bots, built by build_policy_system_prompt; for direct-prompt bots, static + dynamic.
prompt_partsPresent for non-policy bots: mode, cache_enabled, static_system_prompt, dynamic_runtime_prompt, static_version, OpenAI cache-key/retention hints.
opening_messageRendered greeting.
vad, min_words_interruption, re_engagement, ambient_soundPipeline tuning.
stt / llm / ttsBot provider config with the matching api_key injected from system settings. (deepgram_flux STT reuses the deepgram key.)
toolsBot tools, plus an injected detected_voicemail function when voicemail detection is enabled.
conversation_policy, transfer_numbers, transfer_targets, pre_transfer_messageTransfer / policy config.
post_call_analysis_prompt, qc_promptRendered post-call prompts (or null).
post_call_cache_enabled, post_call_cache_version, post_call_cachePost-call explicit-cache controls (combined + per-namespace analysis_version/qc_version).
live_prompt_cache_stateSlimmed {cache_name, expires_at} for the live prompt cache (see Live prompt cache).
sip_context, call_context, crm_contextFlat maps VoxCore uses for tool/transfer template resolution.
knowledgeRAG config (enabled only when both system + bot KB are enabled and KB IDs validate).
callback_detection_enabledTrue only when the linked campaign enables callback detection.
minio, agent_desk_enabled, agent_desk_context, auto_dispositions, voicemail_message, max_call_duration_seconds, timezone, bot_idMisc runtime fields.
The config response also has a side effect: it inserts the call skeleton into db.calls (status: "active") carrying session_id, bot_id, connected_event, sip_context, crm_data, integration_log, and campaign linkage. This is what the post-call results webhook later updates by session_id.

Redis caching + invalidation

The bot document and system settings are read through services/cache_service.py:
KeyTTLSet byInvalidated by
bot:{bot_id}3600s (BOT_CACHE_TTL)set_cached_bot on a Mongo readinvalidate_bot_cache on bot edits
system:settings3600sset_cached_settingsinvalidate_settings_cache on settings edits
Direct MongoDB writes to a bot or to system settings do not invalidate Redis. After an out-of-band DB update, the next call can serve a stale config for up to one hour. Always go through the admin API (which invalidates) or clear the cache key manually.

Operational checks

SymptomFirst place to check
VoxCore gets 403X-VoxCore-Secret mismatch between fleet .env and VoxBridge.
VoxCore gets 404bot_id does not exist, or wrong VoxBridge base URL.
Call rejected with 503 outside_active_hoursbot.active_hours window vs the bot timezone.
Prompt shows literal {{...}}Variable not present in any namespace; check connected_event / CRM pre-fetch.
Stale prompt or provider after an editRedis bot:{bot_id} cache not invalidated.
CRM data missing in promptcrm_pre_fetch config, _skip_prefetch, or pre-fetch timeout (integration_log).

VoxBridge overview

Control-plane responsibilities and module map.

Conversation policy

How policy-engine system prompts are assembled.

VoxCore bot config

How VoxCore consumes the runtime config.

Post-call variables

The full variable catalog across namespaces.