# How to Implement Outbound Calling with LiveKit Agents: A Complete Guide

> Master outbound calling with LiveKit Agents. Learn to create SIP participants and manage call flows using JobContext and WarmTransferTask for seamless agent integrations. Get the complete guide.

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

---

**LiveKit Agents implement outbound calling by creating SIP participants through `JobContext.add_sip_participant()` and managing call flows with `transfer_sip_participant()` or the high-level `WarmTransferTask` workflow.**

The `livekit/agents` repository provides a comprehensive framework for building voice AI agents that can initiate phone calls, transfer callers to human supervisors, and orchestrate complex telephony workflows. To implement outbound calling effectively, you need to understand the SIP participant management APIs in [`livekit-agents/livekit/agents/job.py`](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/job.py) and the warm transfer workflow in the beta workflows module.

## Understanding the Core Components for Outbound Calling

Outbound calling in LiveKit Agents relies on two primary architectural components: the `JobContext` class for low-level SIP operations and the `WarmTransferTask` for high-level workflow orchestration.

### JobContext and SIP Participant Management

The `JobContext` class, defined in [`livekit-agents/livekit/agents/job.py`](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/job.py), exposes methods that interface directly with LiveKit's SIP service. When you implement outbound calling, you interact with two critical methods:

- **`add_sip_participant()`** (lines 28-38): Creates a new SIP participant by dialing out through a configured trunk
- **`transfer_sip_participant()`** (lines 71-84): Moves an existing SIP participant to a new destination

These methods handle the RTP stream establishment and SIP signaling required for telephony integration.

## Creating Outbound Calls with add_sip_participant

To initiate an outbound call, use the `add_sip_participant()` method within your agent's job context. This method requires a valid outbound SIP trunk ID configured in your LiveKit project and a destination phone number or SIP URI.

```python

# Inside an async function with a JobContext instance called `ctx`

sip_participant = await ctx.add_sip_participant(
    call_to="+18005551234",          # Destination phone number or sip:<user>@<host>

    trunk_id="ST_abc123",           # Outbound SIP trunk created in LiveKit

    participant_identity="outbound-call-1",
)

```

Once executed, the call appears as a `RemoteParticipant` in the current room. You can interact with this participant using standard room IO functions, including text-to-speech and speech-to-text pipelines.

## Transferring Calls with transfer_sip_participant

After establishing an outbound call, you may need to redirect the participant to another destination. The `transfer_sip_participant()` method supports both cold transfers (immediate hand-off) and warm transfers (supervised hand-off).

### Cold Transfers

A cold transfer immediately moves the call without intermediary interaction. Set `play_dialtone=True` to provide audio feedback during the transfer process.

```python
await ctx.transfer_sip_participant(
    participant=sip_participant,    # RemoteParticipant or participant identity string

    transfer_to="+18009998877",    # New destination

    play_dialtone=True,
)

```

## Implementing Warm Transfers with WarmTransferTask

For complex scenarios requiring human supervisor intervention, use the `WarmTransferTask` class located 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) (lines 61-84). This high-level workflow orchestrates the complete warm transfer process:

1. Dials a human supervisor using `add_sip_participant`
2. Plays hold music or summary audio while connecting
3. Exposes a `connect_to_caller` tool to the supervisor
4. Merges the calls when the supervisor invokes the tool

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

result = await WarmTransferTask(
    target_phone_number="+18005550000",   # Supervisor number

    sip_trunk_id=os.getenv("LIVEKIT_SIP_OUTBOUND_TRUNK"),
    sip_number=os.getenv("LIVEKIT_SIP_NUMBER"),   # Caller-ID shown to supervisor

    chat_ctx=self.chat_ctx,              # Pass current LLM chat context for summarization

)

# `result.human_agent_identity` contains the SIP participant ID of the supervisor

```

The task automatically handles the SIP participant management internally, using the same `JobContext` methods described earlier.

## Complete Implementation Example

The [`examples/warm-transfer/warm_transfer.py`](https://github.com/livekit/agents/blob/main/examples/warm-transfer/warm_transfer.py) file (lines 21-74) demonstrates a production-ready implementation. This example creates a support agent that can transfer callers to human supervisors using the warm transfer workflow.

```python
class SupportAgent(Agent):
    @function_tool
    async def transfer_to_human(self) -> None:
        await self.session.say("Please hold while I connect you to a human agent.")
        result = await WarmTransferTask(
            target_phone_number=os.getenv("LIVEKIT_SUPERVISOR_PHONE_NUMBER"),
            sip_trunk_id=os.getenv("LIVEKIT_SIP_OUTBOUND_TRUNK"),
            sip_number=os.getenv("LIVEKIT_SIP_NUMBER"),
            chat_ctx=self.chat_ctx,
        )
        await self.session.say(
            "You are now connected to my supervisor.", allow_interruptions=False
        )
        self.session.shutdown()

```

To run this example, configure the following environment variables:
- `LIVEKIT_SUPERVISOR_PHONE_NUMBER`: The phone number to dial for human support
- `LIVEKIT_SIP_OUTBOUND_TRUNK`: Your LiveKit SIP outbound trunk ID
- `LIVEKIT_SIP_NUMBER`: The caller ID number displayed to the callee

## Summary

- **Outbound calling** in LiveKit Agents centers on the `JobContext` class in [`livekit-agents/livekit/agents/job.py`](https://github.com/livekit/agents/blob/main/livekit-agents/livekit/agents/job.py), which provides `add_sip_participant()` for creating calls and `transfer_sip_participant()` for redirecting them.
- **Cold transfers** immediately move callers to new destinations using the transfer method with optional dial-tone playback.
- **Warm transfers** leverage the `WarmTransferTask` workflow 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) to dial supervisors, play hold audio, and merge calls via the `connect_to_caller` tool.
- **Production implementations** should reference the [`examples/warm-transfer/warm_transfer.py`](https://github.com/livekit/agents/blob/main/examples/warm-transfer/warm_transfer.py) example for environment configuration and agent structure.

## Frequently Asked Questions

### What is the difference between cold and warm transfers in LiveKit?

A **cold transfer** uses `JobContext.transfer_sip_participant()` to immediately redirect an active SIP participant to a new phone number without intermediary interaction. A **warm transfer** uses the `WarmTransferTask` workflow to first dial a human supervisor, allow the supervisor to review a summary of the conversation, and then merge the calls only when the supervisor explicitly invokes the `connect_to_caller` tool.

### How do I configure SIP trunking for outbound calling?

You must create an outbound SIP trunk in your LiveKit Cloud or self-hosted LiveKit server dashboard. Obtain the trunk ID (formatted as `ST_xxxxxx`) and pass it as the `trunk_id` parameter to `JobContext.add_sip_participant()` or as `sip_trunk_id` to `WarmTransferTask`. Additionally, set the `sip_number` parameter to control the caller ID displayed to the destination party.

### Can I implement outbound calling without using WarmTransferTask?

Yes. You can implement outbound calling using only the low-level APIs in `JobContext`. Call `add_sip_participant()` to create the outbound call, then use standard room IO methods to interact with the resulting participant. If you need to redirect the call later, invoke `transfer_sip_participant()`. The `WarmTransferTask` is optional and provides convenience for complex supervisor hand-off workflows.

### What environment variables are required for the warm transfer example?

The [`examples/warm-transfer/warm_transfer.py`](https://github.com/livekit/agents/blob/main/examples/warm-transfer/warm_transfer.py) script requires three environment variables: `LIVEKIT_SUPERVISOR_PHONE_NUMBER` (the destination number for the human supervisor), `LIVEKIT_SIP_OUTBOUND_TRUNK` (your LiveKit SIP outbound trunk ID), and `LIVEKIT_SIP_NUMBER` (the caller ID number shown to the supervisor). These variables configure the SIP routing and identity for outbound calls initiated by the agent.