we are using telnyx, livekit cloud, JS sdk and pyt...
# ask-ai
o
we are using telnyx, livekit cloud, JS sdk and python agents to make sip calls. how can i route the call to two different numbers?
t
Thanks for reaching out, fernando. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding to your question about routing a SIP call to two different numbers using Telnyx, LiveKit Cloud, the JS SDK, and Python agents. Short answer • Create an outbound SIP participant for each phone number you want to reach using the agent’s access to LiveKit’s SIP API (i.e., call
create_sip_participant
once per number). Each SIP participant joins the same LiveKit room so both numbers are connected into that room (either sequentially or in parallel). What you can do (high-level) • Sequential dialing (dial number A, then dial number B after A answers or fails). • Parallel ringing / simultaneous dialing (dial A and B at the same time and accept the first to answer). • Put both answered SIP participants into the same LiveKit room to enable mixed audio, conferencing, or bridging logic. Concrete steps and examples 1) Ensure you have an outbound SIP trunk configured (Telnyx) and the
sip_trunk_id
ready. 2) From your Python agent, call
create_sip_participant
once per target number. Example Python agent pattern (conceptual — adapt to your agent scaffolding):
Copy code
# inside your agent function
from livekit import api  # pseudo-import, adapt to actual client

# sequential example
try:
    await api_client.sip.create_sip_participant(
        api.CreateSIPParticipantRequest(
            room_name=ctx.room.name,
            sip_trunk_id=MY_SIP_TRUNK_ID,
            sip_call_to=number1,
            participant_identity=f"sip_{number1}",
            krisp_enabled=True,
            wait_until_answered=True,
        )
    )
    # number1 answered (or connected)
except Exception:
    # handle failure

# then dial second number
try:
    await api_client.sip.create_sip_participant(
        api.CreateSIPParticipantRequest(
            room_name=ctx.room.name,
            sip_trunk_id=MY_SIP_TRUNK_ID,
            sip_call_to=number2,
            participant_identity=f"sip_{number2}",
            krisp_enabled=True,
            wait_until_answered=True,
        )
    )
except Exception:
    # handle failure
Parallel (simultaneous) ringing example using asyncio.gather:
Copy code
await asyncio.gather(
    api_client.sip.create_sip_participant( api.CreateSIPParticipantRequest(..., sip_call_to=number1) ),
    api_client.sip.create_sip_participant( api.CreateSIPParticipantRequest(..., sip_call_to=number2) ),
)
• If you want “first to answer” behavior, call both in parallel and implement logic to keep the first answered participant and hang up the other. • If you want a conference between the two numbers, keep both SIP participants in the same LiveKit room after they answer. 3) Initiate agent invocation from your JS front end (or server) — pass target numbers via metadata or parameters so the Python agent knows which numbers to dial. Notes, limitations, and helpful tips • All routing/bridging must occur through a LiveKit room; there’s no native SIP-only bridging outside the room. • Caller ID: the trunk’s number is normally used. If you need to override caller ID, use the trunk/number override options supported by your Telnyx trunk (subject to Telnyx policies). • Use
wait_until_answered=True
if you need the agent to wait for answer before continuing; omit it to fire-and-forget or to handle answer events asynchronously. • Use
participant_identity
to label SIP participants so you can find/control them later in room participant lists. If you’d like, I can: • Provide a ready-to-run Python agent code sample tailored to your agent framework (please tell me which agent template you’re using). • Show how to implement “first-to-answer” logic (race handling) and cleanly hang up the losing leg. • Walk through how to pass numbers from your JS SDK client into the agent (showing example metadata/dispatch command). Which of those would help you next, and do you have a preferred dialing pattern: sequential, parallel (simultaneous), or conference? Sources: Agents telephony integration | LiveKit Documentation | Outbound Calling Script | LiveKit Documentation | sip | livekit/livekit_composite | DeepWiki | Preserving Caller ID During SIP Transfers in LiveKit Agents | Preserve caller ID during SIP transfers with Twilio | LiveKit
o
we use the js sdk to start the call
t
Thanks — I’m responding to the part where you said you use the JS SDK to start the call. That helps. Quick summary of the recommended flow • The JS SDK typically initiates the overall call/session and signals which phone numbers should be dialed. • A server-side component or Python agent should actually call LiveKit’s SIP API (
create_sip_participant
) once per target number so each SIP leg joins the LiveKit room. • You can start the process from the JS SDK by either calling your backend (preferred) or invoking an agent dispatch endpoint with metadata that includes the numbers. A few quick questions so I can give a precise, actionable example for your setup: 1. Do you already have a Python agent or backend that can call LiveKit’s SIP API? If yes, which one (Python agent template, Express/Flask, etc.)? 2. How do you currently “start the call” from the JS SDK? Options: ◦ You call your backend REST endpoint which then creates the room/dispatches the agent. ◦ You dispatch an agent directly with metadata via LiveKit CLI/API from the client. ◦ Other (please describe). 1. Which dialing behavior do you want when starting from the JS client? ◦ Sequential (call number A, then B), ◦ Parallel/simultaneous (ring both and keep first answer), ◦ Conference (keep both answered legs in the room). 1. Do you need the JS client to wait until at least one number answers before proceeding, or should it just start the dialing and handle events asynchronously? What I can provide next • A short JS → backend flow example showing how to pass numbers from the client to your Python agent. • A concrete Python agent snippet that calls
create_sip_participant
for two numbers (sequential and parallel versions). • Event-handling tips so the JS client can react when a SIP participant connects, answers, or is hung up. Reply with answers to 1–4 and I’ll give a tailored code example (JS + Python agent) for your exact flow.