To put a LiveKit agent on an Indian phone number, buy the number on Edesy, create a LiveKit Cloud inbound trunk and dispatch rule, save the LiveKit SIP URI as an inbound SIP destination, and route the number to it. For outbound, create a LiveKit outbound trunk pointing at your Edesy termination trunk on port 5070.
Start with the number and trunk: Open voice-app.edesy.in — the SIP page has a LiveKit Cloud quick-start that pre-fills these commands with your trunk.
How the pieces fit
| Direction | Who calls whom | What you create |
|---|---|---|
| Inbound | Caller > Edesy number > LiveKit Cloud SIP > room > your agent | LiveKit inbound trunk, dispatch rule, Edesy inbound SIP destination |
| Outbound | Your agent > LiveKit Cloud SIP > Edesy termination trunk > phone network | Edesy termination trunk, LiveKit outbound trunk |
Edesy is the carrier: Indian numbers, KYC, the connection to the phone network, billing in INR. LiveKit Cloud is the media and agent runtime. Your agent code doesn't change; it joins rooms as usual.
What you need
- An Edesy account with KYC done and an Indian number (mobile, landline, toll-free or 92-series).
- A wallet balance (prepaid INR, topped up with Razorpay).
- A LiveKit Cloud project and the
lkCLI logged in to it. - A LiveKit agent that joins rooms (any LiveKit Agents setup).
Part 1: Inbound calls
Step 1: Create the LiveKit inbound trunk
Save this as inbound-trunk.json, using your Edesy number in E.164:
{
"trunk": {
"name": "Edesy inbound",
"numbers": ["+91XXXXXXXXXX"]
}
}Then run:
lk sip inbound create ./inbound-trunk.jsonNote the trunk ID it returns.
Step 2: Add a dispatch rule
A dispatch rule decides which room an incoming call joins. A prefix rule gives each call its own room:
lk sip dispatch create --trunk <SIP_TRUNK_ID> --room-prefix call-Configure your agent to join those rooms (for example with agent dispatch in your LiveKit project).
Step 3: Save LiveKit as an inbound SIP destination on Edesy
Copy your LiveKit project's SIP URI (it looks like sip:xxxx.sip.livekit.cloud). In the Edesy portal, open
SIP, add an Inbound destination named, say, My LiveKit Cloud, and paste the URI.
Each saved destination has a Test call button that places a real call to the URI, so you can confirm LiveKit answers before routing a public number.
Step 4: Route the number
Open the number, set When a call comes in to SIP, and pick My LiveKit Cloud. Call the number from a
mobile. LiveKit should create a room with the call- prefix and your agent should answer.
Part 2: Outbound calls
Step 5: Create an Edesy termination trunk
In Trunks, create a trunk. Each trunk has its own SIP host (tk-xxxxxxxx.trunk.edesy.in), port 5070,
UDP or TCP. For LiveKit Cloud, credentials mode is the simplest, because LiveKit's sending IPs aren't
yours to allowlist. Reveal the password on the trunk page.
Step 6: Create the LiveKit outbound trunk
Save as outbound-trunk.json:
{
"trunk": {
"name": "Edesy outbound",
"address": "tk-xxxxxxxx.trunk.edesy.in:5070",
"numbers": ["+91XXXXXXXXXX"],
"auth_username": "user-xxxxxxxx",
"auth_password": "<password from the trunk page>",
"transport": "SIP_TRANSPORT_AUTO"
}
}numbers lists the Edesy numbers this trunk can call from. Then:
lk sip outbound create ./outbound-trunk.jsonStep 7: Place a test call
lk sip participant create --trunk <SIP_TRUNK_ID> --to +91XXXXXXXXXX --room test-roomYour phone rings with your Edesy number as caller ID. When you answer, you join test-room, where your
agent can speak. In production, create the SIP participant from your backend with the LiveKit server API.
Why route Indian calls through an Indian number provider
LiveKit Cloud handles SIP and media well, but it is not a source of Indian phone numbers. Calls to and from Indian numbers have to reach the phone network through a provider that can issue those numbers, which is the job Edesy does here. On the business side, that means:
- Billing in rupees: a prepaid INR wallet topped up with Razorpay, GST invoices, and GSTIN capture for input tax credit.
- Per-minute pricing: Rs 0.50/min with a 60-second pulse, unanswered calls free, no minimum commitment.
- KYC once: numbers are issued after a one-time KYC review.
- One number, many targets: the same number can later route to an IVR flow, a contact center or a different AI stack without changing what customers dial.
Settings worth checking
| Setting | Where | Why |
|---|---|---|
| Number format | Both trunks | Use E.164 with +91; Indian numbers fail without the country code |
| Max concurrent calls | Edesy trunk page | Caps simultaneous outbound calls; size with how many SIP channels |
| Recording | Per number on Edesy | Turn on if you need call recordings; stored in encrypted cloud storage with signed links |
| Calling hours and consent | Your agent logic | Outbound AI calls in India must respect DND/consent rules |
| SIP TLS and SRTP | Edesy support | Available on request if you need encrypted signalling and media |
When SIP isn't the right path
If you don't want to run LiveKit at all, Edesy numbers can also send raw call audio to your own WebSocket bot (Media Streams, L16 PCM at 8 or 16 kHz, with a Pipecat sample) or exchange text with your bot while Edesy handles speech (Conversation Relay). The SIP trunk for AI voice agents page compares the options, and connecting your own SIP trunk to an AI agent covers bringing an existing carrier.
Troubleshooting
- Inbound call never reaches LiveKit: run the destination's Test call; check the LiveKit inbound trunk lists the exact number in E.164.
- Room created but no agent: the dispatch rule works; check your agent is configured to join rooms with that prefix.
- Outbound 401/403: username or password mismatch on the LiveKit outbound trunk; rotate the password on Edesy and update LiveKit.
- Outbound 404 or invalid number: missing
+91. - No audio: rare with LiveKit Cloud; check that both sides negotiate G.711.
More detail in the LiveKit Cloud guide in the SIP docs and on the SIP trunking page.
Get your Indian number and trunk and have your LiveKit agent answering in an afternoon.