# How to Configure Telephony Integration with SIP in LiveKit Agents

> Configure telephony integration with SIP in LiveKit Agents by provisioning a SIP trunk exporting environment variables and using JobContext to manage inbound and outbound calls.

- Repository: [LiveKit/agents](https://github.com/livekit/agents)
- Tags: how-to-guide
- Published: 2026-03-06

---

**To configure telephony integration with SIP in LiveKit Agents, provision a LiveKit SIP trunk, export the `LIVEKIT_SIP_OUTBOUND_TRUNK` and `LIVEKIT_SIP_NUMBER` environment variables, and use `JobContext.add_sip_participant()` to place outbound calls or handle inbound calls via dispatch rules.**

LiveKit Agents enables AI voice agents to place outbound calls and receive inbound calls through the PSTN using SIP (Session Initiation Protocol) integration. This guide covers the complete setup process using the `livekit/agents` repository, including trunk configuration, API implementation, and advanced warm-transfer workflows.

## Prerequisites and Environment Configuration

Before implementing SIP functionality, you must provision a SIP trunk on your LiveKit server and configure the required environment variables.

First, create an outbound SIP trunk through the LiveKit console or API, noting the trunk ID (formatted as `ST_xxxxxx`). Then export the following variables in your agent's runtime environment:

```bash
export LIVEKIT_URL=wss://your.livekit.server
export LIVEKIT_API_KEY=your_api_key
export LIVEKIT_API_SECRET=your_api_secret

# Outbound trunk ID from your LiveKit SIP configuration

export LIVEKIT_SIP_OUTBOUND_TRUNK=ST_abcxyz

# Caller ID that appears on the recipient's phone (E.164 format)

export LIVEKIT_SIP_NUMBER=+15005006000

```

## Placing Outbound SIP Calls

Once configured, agents can initiate PSTN calls programmatically. The system treats SIP participants as standard remote participants within LiveKit rooms, allowing bidirectional audio streaming and standard agent API interactions.

### Direct SIP Dialing with add_sip_participant

Use the `add_sip_participant` method on the `JobContext` object to dial a phone number and add the resulting SIP participant to the current room. This method is implemented in [`livekit-agents/livekit/agents/job.py#L528-L570`](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/job.py#L528-L570).

```python
import os
from livekit.agents import JobContext

async def dial_outbound(ctx: JobContext):
    # Initiate the call to a PSTN number

    sip_future = ctx.add_sip_participant(
        call_to="+15551234567",          # Destination phone number (E.164)

        trunk_id=os.getenv("LIVEKIT_SIP_OUTBOUND_TRUNK"),
        participant_identity="customer-call",
    )
    
    # Wait for the call to be answered (optional, based on wait_until_answered parameter)

    sip_info = await sip_future  # Returns api.SIPParticipantInfo

```

By default, `add_sip_participant` returns immediately. Pass `wait_until_answered=True` to block until the callee answers.

### Implementing Warm Transfers

For call-center scenarios requiring "hold-and-transfer" functionality, use the `WarmTransferTask` class from the beta workflows module. This high-level helper automates creating a supervisor room, dialing via SIP, playing hold music, and merging calls upon connection.

The implementation resides in [[`livekit-agents/livekit/agents/beta/workflows/warm_transfer.py`](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/beta/workflows/warm_transfer.py)](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/beta/workflows/warm_transfer.py).

```python
from livekit.agents.beta.workflows import WarmTransferTask

async def transfer_to_supervisor(ctx: JobContext):
    result = await WarmTransferTask(
        target_phone_number="+15559876543",   # Supervisor's phone number

        sip_trunk_id=os.getenv("LIVEKIT_SIP_OUTBOUND_TRUNK"),
        sip_number=os.getenv("LIVEKIT_SIP_NUMBER"),
        hold_audio=AudioConfig.BuiltinAudioClip.HOLD_MUSIC,
    )
    
    # Access the supervisor's participant identity after connection

    supervisor_id = result.human_agent_identity

```

## Handling Inbound SIP Calls

To receive incoming PSTN calls, define a dispatch rule that routes SIP traffic to a specific agent entrypoint. When a call arrives, LiveKit creates a room and invokes your registered handler with the SIP participant already connected.

```python
from livekit.agents import AgentServer, AgentSession, JobContext

server = AgentServer()

@server.rtc_session(agent_name="sip-inbound")
async def inbound_entrypoint(ctx: JobContext):
    # SIP caller is available in ctx.room.remote_participants

    session = AgentSession(
        vad=silero.VAD.load(),
        llm="openai/gpt-4.5-mini",
        stt="deepgram/nova-3:en",
        tts="cartesia/sonic-3:default",
    )
    await session.start(agent=my_agent, room=ctx.room)

```

See the complete inbound handling implementation in [[`examples/warm-transfer/warm_transfer.py`](https://github.com/livekit/agents/blob/main/examples/warm-transfer/warm_transfer.py)](https://github.com/livekit/agents/blob/main/examples/warm-transfer/warm_transfer.py).

## Room Configuration for SIP Participants

By default, `RoomOptions` accepts both standard and SIP participants. You can explicitly control participant acceptance using the `participant_kinds` parameter defined in [`livekit-agents/livekit/agents/voice/room_io/types.py#L18-L22`](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/voice/room_io/types.py#L18-L22).

```python
from livekit import rtc
from livekit.agents.voice.room_io import RoomOptions

# Restrict room to SIP participants only

room_opts = RoomOptions(
    participant_kinds=[rtc.ParticipantKind.PARTICIPANT_KIND_SIP]
)

```

For telephony-specific audio processing, enable noise cancellation optimized for PSTN audio:

```python
from livekit.plugins import noise_cancellation
from livekit.agents.voice.room_io import AudioInputOptions

room_opts = RoomOptions(
    audio_input=AudioInputOptions(
        noise_cancellation=noise_cancellation.BVCTelephony()
    )
)

```

## Summary

- **Configure environment variables**: Export `LIVEKIT_SIP_OUTBOUND_TRUNK` (trunk ID) and `LIVEKIT_SIP_NUMBER` (caller ID) before starting your agent.
- **Place outbound calls**: Use `JobContext.add_sip_participant()` from [`livekit/agents/job.py`](https://github.com/livekit/agents/blob/main/livekit/agents/job.py) to dial PSTN numbers programmatically.
- **Handle complex workflows**: Implement `WarmTransferTask` for hold-and-transfer scenarios without manual room management.
- **Receive inbound calls**: Register dispatch rules for SIP traffic; participants appear as standard remote participants in `ctx.room`.
- **Optimize configuration**: Set `RoomOptions` with `BVCTelephony()` noise cancellation and appropriate `participant_kinds` for telephony-specific behavior.

## Frequently Asked Questions

### What environment variables are required for SIP integration?

You must export `LIVEKIT_SIP_OUTBOUND_TRUNK` containing your outbound trunk ID (e.g., `ST_abcxyz`) and `LIVEKIT_SIP_NUMBER` containing the E.164 caller ID (e.g., `+15005006000`). These variables are read by the agent process to authenticate and route calls through your LiveKit SIP infrastructure.

### How do I handle inbound versus outbound SIP calls differently?

For **outbound** calls, use `ctx.add_sip_participant()` within an active agent session to dial a number and add the resulting participant to the current room. For **inbound** calls, create a dispatch rule that routes SIP traffic to a specific agent entrypoint; the SIP participant will already be present in `ctx.room.remote_participants` when your handler executes.

### What is the difference between add_sip_participant and WarmTransferTask?

`add_sip_participant` is a low-level API that dials a single phone number and adds the participant to your room. `WarmTransferTask` is a high-level workflow that manages complex call-center scenarios: it creates a separate supervisor room, plays hold music to the original caller, dials the supervisor via SIP, and automatically merges the calls when the supervisor answers.

### How do I configure caller ID for outbound SIP calls?

Set the `LIVEKIT_SIP_NUMBER` environment variable to the E.164 phone number you want displayed on the recipient's caller ID. This number must be associated with your LiveKit SIP trunk configuration. When using `add_sip_participant` or `WarmTransferTask`, the system uses this variable as the default caller ID for all outbound PSTN calls.