Inbound Call Flow
Inbound calling currently uses the custom Exotel SIP bridge.
Routing Steps
- Exotel sends a SIP
INVITEto the custom inbound bridge. - The bridge reads the dialed number from the SIP
Toheader. - The number is normalized with the same formatter used by the
/inboundAPI. - The bridge looks up an active
InboundSIPmapping byphone_number_normalized. - If the mapping is missing or detached, the bridge returns
480 Temporarily Unavailable. - The bridge loads the assistant from
assistant_idon the mapping. - If the mapped assistant is inactive or missing, the bridge returns
480 Temporarily Unavailable. - When routing succeeds, the bridge creates a LiveKit room, dispatches the assistant, and connects RTP audio.
- The agent session optionally runs inbound context lookup before rendering prompt templates.
Dispatch Metadata
The bridge creates the LiveKit dispatch with these metadata keys:
| Key | Value |
|---|---|
call_type |
inbound |
service |
exotel |
assistant_id |
Assistant selected from the mapping |
assistant_name |
Assistant display name |
inbound_id |
Inbound mapping identifier |
inbound_context_strategy_id |
Optional strategy attached to the mapping |
inbound_number |
Normalized dialed number |
caller_number |
Parsed caller number from the SIP From header |
Agent Prompt Rendering Phase
After dispatch, the worker loads metadata and renders:
assistant_promptassistant_start_instruction
Render inputs are:
- Existing top-level metadata keys.
call.*namespace containing the call metadata.- Optional
context.*namespace when inbound context lookup succeeds.
Optional Strategy and Fallback Behavior
If inbound_context_strategy_id is not present:
- No lookup is attempted.
- Prompt rendering continues using call metadata only.
If inbound_context_strategy_id is present:
- The worker tries to load the strategy and call the configured webhook.
- The webhook must return JSON with a top-level
contextobject. - Full request/response contract is documented in Inbound Context Strategies.
If strategy loading or webhook lookup fails:
- Timeout, HTTP error, invalid JSON, invalid payload shape, missing URL, or inactive strategy all fall back to default prompt behavior.
- The call continues and the assistant still starts.
- An
inbound_context_lookupactivity log is written for attempted lookups.
Runtime Notes
- A
200 OKSIP response is sent only after LiveKit room setup and RTP bridge startup succeed. - The bridge waits briefly after room connection, then publishes a
call_answeredevent on thesip_bridge_eventstopic so the agent can start speaking after the media path is ready. - If room creation or dispatch setup fails, the bridge returns
500 Internal Server Error. - Active call shutdown is driven by SIP
BYE, LiveKit disconnect, or RTP silence timeout.
sequenceDiagram
participant Caller
participant Exotel
participant Bridge as Exotel Inbound Bridge
participant DB as MongoDB
participant LK as LiveKit
participant Agent as Agent Worker
participant Webhook as Context Webhook
Caller->>Exotel: Dial Exotel number
Exotel->>Bridge: SIP INVITE
Bridge->>Bridge: Normalize dialed number
Bridge->>DB: Lookup active inbound mapping
DB-->>Bridge: mapping (assistant_id + optional strategy_id) or no match
alt No mapping or detached mapping
Bridge-->>Exotel: 480 Temporarily Unavailable
else Mapping found
Bridge->>DB: Load assistant
Bridge->>LK: Create room and dispatch agent
Bridge-->>Exotel: 200 OK
LK->>Agent: Start session with dispatch metadata
alt strategy_id exists
Agent->>DB: Load active strategy
alt Strategy found
Agent->>Webhook: POST caller/context lookup
alt Valid response {context: {...}}
Webhook-->>Agent: context payload
else Timeout or invalid response
Webhook-->>Agent: error or invalid payload
end
else Strategy missing/inactive
Agent->>Agent: Skip lookup and continue
end
else No strategy
Agent->>Agent: Continue without lookup
end
Agent->>Agent: Render prompt/start instruction
Bridge->>Agent: Publish call_answered event
Exotel->>Bridge: RTP audio
Agent->>Bridge: RTP audio
end