I have a backend system that creates and tracks li...
# ask-ai
m
I have a backend system that creates and tracks livekit rooms in livekit cloud, and I have a TwiML app which can talk to the backend system. I want my TwiML app to dial out (to customers) and bridge them into specific pre-existing livekit rooms that my backend created. Sometimes multiple outbound calls must be bridged into the same preexisting room. What is the recommended way of doing this?
t
Thanks for reaching out, Amanda. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — this is a clear question. I’m responding to your goal of dialing out from a TwiML app and bridging those outbound calls into specific pre-existing LiveKit rooms (including multiple outbound callers into the same room). Recommended approach (short summary) • Use LiveKit’s SIP inbound trunk + SIP dispatch rules to accept calls from Twilio and route each call into the correct pre-existing room. • Have your TwiML app place outbound calls to phone numbers/DIDs that LiveKit owns or routes for, and configure dispatch rules so calls to those numbers are bridged into the desired room. Multiple calls to the same routed number will join the same room as separate SIP participants. Why this is recommended • LiveKit’s SIP inbound trunk + dispatch model is designed to map SIP INVITEs to LiveKit rooms and participants reliably. • It avoids brittle direct TwiML/SIP-to-WebRTC bridging logic on your side and gives deterministic routing (so many outbound callers can be placed into the same room cleanly). High-level steps to implement 1. Reserve or assign a phone number (DID) for each room (or for groups of rooms if you prefer a shared number). 2. Configure a Twilio SIP trunk (or configure your TwiML app to dial the number) so the outbound call is sent to LiveKit’s SIP endpoint. 3. In LiveKit, create a SIP inbound trunk that accepts calls from Twilio (use IP allowlisting or credentials as required). 4. Create a SIP dispatch rule that maps the inbound number (or other SIP routing criteria) to the pre-existing room using a direct dispatch (e.g.,
dispatchRuleDirect
with the
room_name
). 5. Optionally, have your backend manage trunks and dispatch rules programmatically via the LiveKit server/API when you create rooms, so routing stays in sync. 6. Test: when Twilio dials the number, LiveKit receives an INVITE, applies the dispatch rule, and adds the call as a SIP participant to the target room. Multiple callers to that number will appear as separate SIP participants in the same room. Notes and options • One number per room: simplest mapping and easiest to reason about. • Shared number for many callers into one room: works fine — all calls to that number are routed to the same room. • Programmatic management: creating trunks and dispatch rules from your backend when rooms are created makes lifecycle management simple and avoids manual config drift. • Media handling: LiveKit converts SIP/RTP to WebRTC internally, so the bridged callers will behave as participants inside the room. If you’d like, I can: • Walk through an example dispatch rule JSON for mapping a phone number to an existing room. • Show a short Python example of creating a trunk + dispatch rule from your backend. • Help you choose between one-number-per-room vs shared-number rules based on your expected call volume and operational needs. Which follow-up would be most helpful: example dispatch JSON, SDK code for automating trunk/rule creation, or guidance on number assignment strategy? Sources: Outbound Calling Script | LiveKit Documentation | Accepting calls overview | LiveKit Documentation | Agents telephony integration | LiveKit Documentation | sip | livekit/livekit_composite | DeepWiki | How to do call transfers with Five9 | LiveKit
m
I am iffy about dynamically creating dispatch rules like that. Assume the volume is high and the backend is constantly creating. managing, and tearing down many rooms. Or is there another way to manage dispatch rules so that they expire with the room?
t
Thanks — great follow-up. I’m responding to your concern about dynamically creating & deleting SIP dispatch rules for every room in a high-volume environment. Short answer • Do NOT create a dispatch rule per room. Dispatch rules are intended to be long-lived control-plane resources and do not need to (and should not) be created/expired with each room. • Use a small set of persistent dispatch rules that route calls to dynamically created rooms (for example via
room_prefix
or an individual dispatch rule pattern). This scales cleanly and avoids per-room management overhead. Why this works at scale • A single dispatch rule can route unlimited calls by mapping an inbound call to a room name pattern (e.g.,
call-<id>
). LiveKit will create the room/participant on demand and you can tear the room down when the call ends. • Dispatch rules are stable configuration items. They remain active across many rooms and calls; rooms are ephemeral and their lifecycle is separate from the rule. • This avoids frequent API churn, race conditions, and complexity of synchronizing rule lifecycle with room lifecycle. Recommended patterns 1) Persistent rule with room prefix (recommended for high volume) • Create one dispatch rule for the trunk/number that sets a
room_prefix
(e.g.,
call-
). • When Twilio dials the number, LiveKit uses the rule to route to a room like
call-abc123
. Your backend or LiveKit can create the room on demand or LiveKit can provision it when the INVITE arrives. • Clean up rooms after calls (auto-delete on close or your cleanup task). The dispatch rule stays. 2) Persistent rule with dispatchRuleIndividual for predictable room IDs • Use the rule to accept a parameter (or header) that forms the room name, allowing deterministic routing without creating many rules. 3) Use metadata in roomConfig for extra routing/behavior • Keep dispatch rules static and use per-call metadata or participant metadata for routing logic (agent assignment, flows, features). This lets you vary behavior without new rules. Operational best practices • Create dispatch rules once during provisioning, not per call. Only delete rules when you decommission the number/trunk or change routing permanently. • Rely on room lifecycle for cleanup: delete rooms when the call/meeting ends. Dispatch rules do not need to be deleted to reclaim resources. • Monitor trunk and rule usage (metrics/logs) rather than per-room rule creation metrics. • If you need per-call custom routing, encode information in the SIP headers or dialed DID and have the persistent rule map that into a room name or metadata—still no per-room rule required. When (rarely) to delete a dispatch rule • Retiring the phone number or trunk. • Replacing routing logic globally (not for individual rooms). You should not attempt to have rules “expire” automatically with rooms; instead, rely on ephemeral rooms + persistent rules. If you want, I can: • Show a concrete dispatch rule JSON using
room_prefix
. • Show an example flow (Twilio -> trunk -> dispatch rule -> room creation) with a short SDK snippet for creating rooms and cleaning them up. • Help choose number-per-room vs shared-number patterns given your call volume and agent topology. Which example would help you the most right now: rule JSON, SDK automation snippet, or a recommended number-mapping strategy? Sources: sip | livekit/livekit_composite | DeepWiki | Outbound Calling Script | LiveKit Documentation
m
When Twilio dials the number, LiveKit uses the rule to route to a room like
call-abc123
. Your backend or LiveKit can create the room on demand or LiveKit can provision it when the INVITE arrives.
How do I have my backend create the room beforehand, and NOT have Livekit create the room when the inbound call arrives? Give me an example dispatch rule and inbound trunk config
t
Thanks — I’m responding to your request for a concrete example that prevents LiveKit from auto-creating rooms when a Twilio call arrives, and instead ensures the backend creates the room beforehand. Key points up front • Make sure your backend creates the LiveKit room before Twilio dials the number. The dispatch rule will route the call to the named room; if the room does not exist LiveKit may create it. So pre-create the room and keep it alive until the call completes. • Use a dispatch rule that routes by an explicit room name (not a room_prefix that triggers on-demand naming). Use
dispatchRuleDirect
(or an individual dispatch rule variant that points to
room_name
) so the rule targets a specific room name. • Configure the inbound trunk to accept calls from Twilio and associate the dispatch rule with that trunk. Example flow 1. Backend: create room
customer-support-123
in LiveKit before dialing. 2. Twilio: dials the DID associated with your LiveKit trunk. 3. LiveKit inbound trunk receives INVITE, applies the dispatch rule which routes to
customer-support-123
. 4. Because the room already exists, the call is bridged into that pre-existing room. Example: dispatch rule JSON (routes to an explicit pre-created room)
Copy code
{
  "trunk_ids": [
    "trunk-abc123"
  ],
  "rule": {
    "dispatchRuleDirect": {
      "room_name": "customer-support-123"
    }
  },
  "roomConfig": {
    "agents": []
  }
}
Notes: •
trunk_ids
ties this rule to your inbound trunk(s). •
dispatchRuleDirect.room_name
is the explicit room name to route to. This prevents pattern-based dynamic room naming. • You can create one or more rules like this for known rooms or generate unique but static rules per known DID — but avoid creating rules per short-lived room at high volume. Example: inbound SIP trunk config (accept calls from Twilio)
Copy code
{
  "trunk": {
    "name": "twilio-inbound-trunk",
    "sip_trunk_type": "INBOUND",
    "numbers": [
      "+15551234567"
    ],
    "allowed_addresses": [
      "54.251.250.0/24",
      "54.251.251.0/24"
    ],
    "auth": {
      "type": "IP_ALLOWLIST"
    }
  }
}
Notes: •
numbers
lists the DID(s) Twilio will dial. Associate the dispatch rule(s) with the trunk that owns these numbers. •
allowed_addresses
should include Twilio egress IP ranges or use credentials if you prefer authentication. • Ensure the trunk is configured to use the dispatch rules you created. Backend room creation example (conceptual) • Before triggering Twilio to dial, your backend should create the LiveKit room named
customer-support-123
via the LiveKit server API/SDK and ensure it remains available until the call ends. • Typical steps: a. Call LiveKit API to create room
customer-support-123
. b. Optionally set
delete_room_on_close
= false (or ensure your cleanup logic only deletes after the call completes). c. Trigger Twilio to place the outbound call to
+15551234567
. Important operational details • If the dispatch rule points to a room name that does not exist, LiveKit may create the room when the INVITE arrives. To prevent that, ensure the room is created by your backend in advance. • Use explicit
room_name
dispatch rules instead of
room_prefix
when you need guaranteed routing to pre-created rooms. • Manage trunk allowlist/auth so only Twilio can send INVITEs. • For high-volume systems, prefer persistent dispatch rules mapping DIDs to persistent rooms or to naming schemes you control; avoid creating/deleting rules per ephemeral room. If you’d like, I can: • Provide a concrete SDK snippet (Python/Node) showing: create room -> confirm creation -> trigger Twilio dial. • Show how to associate multiple DIDs to different pre-created rooms and a sample cleanup flow to delete rooms after calls end. Which follow-up do you want first: SDK room-creation snippet or the Twilio dial sequencing example?