Guide

Give a Pipecat voice agent an Indian phone number

Connect a Pipecat agent to the Indian phone network through LiveKit SIP and a RingTrunk trunk. Inbound calls land in a LiveKit room, the Pipecat pipeline joins with LiveKitTransport, and outbound calls are placed with the LiveKit API.

Updated 6 September 2026

In short: A Pipecat agent gets an Indian phone number through LiveKit SIP on a RingTrunk trunk: calls land in a LiveKit room, and the Pipecat pipeline joins it with the LiveKit transport.

Pipecat does not speak SIP itself. It joins a LiveKit room, and LiveKit's SIP service bridges the phone call into that room. So a Pipecat agent gets an Indian phone number in two layers: LiveKit connected to your RingTrunk trunk, and a Pipecat pipeline that joins the room where the caller lands.

1. Connect LiveKit to RingTrunk

Follow Connect LiveKit Cloud or Connect self-hosted LiveKit. Create the dispatch rule without room_config.agents. Pipecat is not a LiveKit Agents worker, so it is not dispatched that way.

2. Start the pipeline when a call arrives

Subscribe to LiveKit webhooks for room_started or participant_joined, and start a Pipecat pipeline for that room. The transport joins the room with an access token:

Pipecat 1.x with the LiveKit transport
from livekit import api
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.transports.services.livekit import LiveKitParams, LiveKitTransport


def agent_token(room_name: str) -> str:
    return (
        api.AccessToken()
        .with_identity("agent")
        .with_grants(api.VideoGrants(room_join=True, room=room_name))
        .to_jwt()
    )


transport = LiveKitTransport(
    url=LIVEKIT_URL,
    token=agent_token(room_name),
    room_name=room_name,
    params=LiveKitParams(
        audio_in_enabled=True,
        audio_out_enabled=True,
        vad_analyzer=SileroVADAnalyzer(),
    ),
)

# Build the pipeline as usual:
# transport.input() -> STT -> LLM -> TTS -> transport.output()

The caller's audio arrives on the transport input; the agent's speech goes back to the caller through the transport output.

3. Place a call from the agent

Create the room, start the pipeline, then add the phone leg with the LiveKit API. The caller ID must be a number attached to your RingTrunk trunk.

Outbound call
from livekit import api

lkapi = api.LiveKitAPI()
await lkapi.sip.create_sip_participant(
    api.CreateSIPParticipantRequest(
        sip_trunk_id="<YOUR_OUTBOUND_TRUNK_ID>",
        sip_call_to="+91XXXXXXXXXX",
        sip_number="9XXXXXXXXX",
        room_name=room_name,
    )
)

Destinations are Indian mobile numbers only, 10 digits starting 6, 7, 8 or 9.

Audio on the phone leg

The call leg is G.711 A-law at 8 kHz. LiveKit converts between the phone leg and the room, so the pipeline does not need to know it is on a phone call. Telephony-tuned speech recognition still helps, as it does on any phone audio.

Working example

A runnable version of this page, with a webhook server that starts the bot when a call lands and a script that places calls, is at github.com/Zingaro-Ai/ringtrunk-livekit-example (MIT).

In production

Zingaro AI's phone agents are Pipecat pipelines answering Indian numbers exactly this way, through LiveKit Cloud and a RingTrunk trunk. The setup above is the one they run.