VonyxDocs

LiveKit

Connect LiveKit Agents to Vonyx numbers over a SIP trunk, for outbound and inbound calls.

View this page as Markdown

Point a LiveKit outbound trunk at Vonyx so your agents can dial Indian numbers, and forward your Vonyx number to your LiveKit SIP endpoint so callers reach an agent. Both directions use plain SIP over UDP or TCP.

Before you start

Outbound calls

Create an outbound trunk

The outbound trunk tells LiveKit where to send the SIP INVITE and which credentials to use.

FieldValue
address43.204.9.41 (hostname or IP only, no sip:; Vonyx listens on the default port 5060)
numbersYour Vonyx number, 91XXXXXXXXXX. LiveKit uses it as the caller ID.
destination_countryin, so LiveKit places the call from its India region
auth_username / auth_passwordYour Vonyx trunk username and password
outbound-trunk.json
{
  "trunk": {
    "name": "Vonyx outbound",
    "address": "43.204.9.41",
    "numbers": ["91XXXXXXXXXX"],
    "destination_country": "in"
  }
}

Pass the credentials as flags so they stay out of the file:

lk sip outbound create outbound-trunk.json \
  --auth-user "your_trunk_username" \
  --auth-pass "your_trunk_password"

The command prints SIPTrunkID: ST_…. Save it. You can list trunks later with lk sip outbound list.

You can also create the trunk in LiveKit Cloud under Telephony → SIP trunks → Create new trunk → JSON editor, with Trunk direction set to Outbound. That editor takes the object without the trunk wrapper and accepts auth_username and auth_password directly.

Leave transport unset (auto) or set it to UDP or TCP. Don't turn on media encryption: Vonyx doesn't support TLS or SRTP.

Place a test call from the CLI

Create a SIP participant. LiveKit dials sip_call_to through the trunk and puts the callee in room_name.

sip-participant.json
{
  "sip_trunk_id": "ST_xxxxxxxx",
  "sip_call_to": "91XXXXXXXXXX",
  "room_name": "vonyx-test",
  "participant_identity": "callee",
  "participant_name": "Test callee",
  "wait_until_answered": true
}
lk sip participant create sip-participant.json

With wait_until_answered, the command returns once the callee picks up. This call has no agent in the room, so you only confirm that the phone rings and the call connects.

Dial from your agent

In your agent's entrypoint, read the number from the job metadata and create the SIP participant in the agent's own room. This follows LiveKit's outbound example for the Python livekit-agents / livekit-api packages.

agent.py
import json
 
from livekit import agents, api
 
# server = AgentServer(...)  # from the LiveKit voice AI quickstart
 
@server.rtc_session(agent_name="YOUR_AGENT_NAME")
async def entrypoint(ctx: agents.JobContext):
    phone_number = json.loads(ctx.job.metadata or "{}").get("phone_number")
 
    if phone_number:
        try:
            await ctx.api.sip.create_sip_participant(api.CreateSIPParticipantRequest(
                room_name=ctx.room.name,
                sip_trunk_id="ST_xxxxxxxx",      # your Vonyx outbound trunk
                sip_call_to=phone_number,        # 91XXXXXXXXXX
                participant_identity=phone_number,
                wait_until_answered=True,
            ))
        except api.SipCallError as e:
            print(f"call failed: {e.sip_status_code} {e.sip_status}")
            ctx.shutdown()
            return
 
        participant = await ctx.wait_for_participant(identity=phone_number)
        # session = AgentSession(...)
        # await session.start(room=ctx.room, participant=participant, agent=Assistant())
        # Let the callee speak first on outbound calls.

To place a different caller ID per call, set sip_number on the request to another of your Vonyx numbers instead of creating a new trunk.

Dispatch the agent with a number

Start a job for the agent in a new room and pass the number to dial:

lk dispatch create \
  --new-room \
  --agent-name YOUR_AGENT_NAME \
  --metadata '{"phone_number": "91XXXXXXXXXX"}'

From a backend, use lkapi.agent_dispatch.create_dispatch(api.CreateAgentDispatchRequest(agent_name=..., room=..., metadata=...)) instead.

Inbound calls

Find your LiveKit SIP endpoint

Your SIP URI is on the Project settings page in LiveKit Cloud and looks like sip:abc123xyz.sip.livekit.cloud. The SIP endpoint is the same value without sip:.

You can also build it from the CLI: run lk project list --json, take the ProjectId (for example p_abc123xyz) and drop the p_ prefix.

To keep calls in India, you can use the region endpoint abc123xyz.india.sip.livekit.cloud instead.

Create an inbound trunk

The inbound trunk accepts calls to your Vonyx number.

inbound-trunk.json
{
  "trunk": {
    "name": "Vonyx inbound",
    "numbers": ["91XXXXXXXXXX"]
  }
}
lk sip inbound create inbound-trunk.json

Save the trunk ID it prints.

Restricting by IP

LiveKit's allowed_addresses field could limit the trunk to 43.204.9.41, but LiveKit must enable it for your project first (contact LiveKit support). Without it, the numbers list is what restricts the trunk.

Add a dispatch rule that sends calls to your agent

The dispatch rule puts each caller in a new room (prefixed call-) and dispatches your agent to it through room_config.agents. The agent_name must match the name in your agent's rtc_session decorator.

dispatch-rule.json
{
  "dispatch_rule": {
    "name": "Vonyx to agent",
    "trunk_ids": ["ST_inbound_xxxxxxxx"],
    "rule": {
      "dispatch_rule_individual": {
        "room_prefix": "call-"
      }
    },
    "room_config": {
      "agents": [{ "agent_name": "YOUR_AGENT_NAME" }]
    }
  }
}
lk sip dispatch create dispatch-rule.json

If you leave out trunk_ids, the rule matches every inbound trunk. In the agent, ctx.job.metadata is empty on inbound calls unless you set metadata on the agent entry, so the code above skips dialing and the agent can greet the caller.

Point Vonyx at LiveKit

In the Vonyx console, open your trunk, turn on Inbound calls and set the Inbound address to your SIP endpoint, for example abc123xyz.sip.livekit.cloud. Leave out sip: and any user part. See Inbound calls.

Vonyx then forwards calls to the attached number from 43.204.9.41.

Test the connection

  1. Outbound: run lk sip participant create sip-participant.json with your own phone as sip_call_to. Your phone should ring with your Vonyx number as caller ID.
  2. Agent outbound: start your agent in dev mode and run the lk dispatch create command above. The agent should talk once you answer.
  3. Inbound: with the agent running, call your Vonyx number. A room named call-… should appear in LiveKit Cloud with a SIP participant and your agent.

The SIP participant's sip.callStatus attribute is active once a call connects, and sip.trunkPhoneNumber shows the number LiveKit matched on.

Limitations

  • DTMF and call transfer are not available on Vonyx yet, so don't rely on LiveKit's dtmf field, DTMF events or TransferSIPParticipant.
  • New accounts make 1 call at a time (raise limits).
  • No TLS or SRTP: keep LiveKit transport on UDP, TCP or auto, and media encryption off.
  • Codecs are PCMU and PCMA only.
  • Caller ID (numbers or sip_number) must be one of your Vonyx numbers.

Troubleshooting

ProblemFix
SipCallError with 401 or 407The trunk username or password is wrong. Re-create the trunk with the right --auth-user and --auth-pass.
Outbound call rejected right awayCheck the caller ID in numbers (or sip_number) is one of your Vonyx numbers and the dialled number is 91XXXXXXXXXX.
SipCallError with 486 or 603The callee rejected the call.
SipCallError with 408 or 480No answer or the callee was unreachable.
Second parallel call failsNew accounts have 1 channel. See limits.
Inbound call never reaches LiveKitCheck the inbound address has no sip: prefix and that Inbound calls is on.
Inbound call reaches LiveKit but is rejectedThe called number didn't match the trunk's numbers. Add the format Vonyx sends, or check trunk_ids on the dispatch rule.
Room is created but no agent joinsThe agent_name in the dispatch rule doesn't match the agent's rtc_session(agent_name=...), or the agent isn't running.
Call connects with no audioVonyx sends RTP over UDP 10000–20000 with PCMU or PCMA only. Don't restrict LiveKit's codecs to others. See SIP troubleshooting.