early-butcher-66889
02/28/2026, 5:58 PMtall-airline-16756
02/28/2026, 5:58 PMtall-airline-16756
02/28/2026, 5:58 PMwait_until_answered / equivalent) so you don’t drop before the target answers.
• Once the new party is joined in the same LiveKit room, have the agent leave the room (disconnect) so the two parties remain connected without the agent.
Why this works
• This avoids SIP REFER and performs a cold transfer by bridging a new participant into the room.
• The room remains active for the new participant after the agent drops off.
• You can preserve caller ID on the outbound leg by passing the appropriate sip_number if you need the original caller ID shown to the callee.
Practical considerations
• Ensure wait_until_answered (or equivalent) is used so the agent only leaves after the call is answered.
• Make the outbound participant identity distinct (e.g., transfer_<number>) so you can track that participant in the room and handle any post-join logic or cleanup.
• If you need the callee to see the original caller ID, set sip_number to the original caller’s number when creating the outbound participant.
• Handle failures: if the outbound call fails or is unanswered, the agent should notify the caller and either retry or reconnect.
Example flow (high level)
1. Agent receives instruction to transfer to +1-555-123-4567.
2. Agent calls the LiveKit API to create an outbound SIP participant that dials +1-555-123-4567 with wait_until_answered=true.
3. When the outbound leg answers and joins the room, agent informs the caller (optional) and disconnects.
4. Room stays active between caller and callee.
If you want, I can:
• Provide a short code snippet for your platform (Node/Python) showing the API call and wait logic.
• Suggest error-handling flows (retry, fallback options).
• Outline how to preserve caller ID in your outbound request.
Which would be most helpful next?
Sources: Agents telephony integration | LiveKit Documentation | Preserving Caller ID During SIP Transfers in LiveKit Agents | Outbound Calling Script | LiveKit Documentationearly-butcher-66889
02/28/2026, 6:00 PMtall-airline-16756
02/28/2026, 6:00 PMAgentSession / JobContext and credentials needed to call create_sip_participant, so it can perform the action without extra hops.
• Agents are designed to act as stateful bridges between LLM decision-making and real-time actions (dialing, adding participants), so initiating the outbound call from the agent aligns with intended patterns.
• Direct calls avoid added latency, complexity, and failure points that come from routing through an extra external service.
When to consider using an external API instead
• You need centralized auditing, richer logging, or regulatory compliance that must be kept outside of ephemeral agent sessions.
• You want a single, hardened control plane for access control, rate limiting, or cross-service orchestration (e.g., notify billing systems, update CRM, trigger other downstream workflows).
• You need to share a single outbound trunk/credential set that you don’t want exposed to many agent instances for security reasons.
Practical best practices if the agent calls LiveKit directly
• Use wait_until_answered so the agent doesn’t drop before the outbound leg connects.
• Give the outbound participant a clear identity (e.g., transfer_<phone>) so it’s easy to track and clean up.
• Store credentials securely (environment variables, secrets store) and scope them with least privilege.
• Implement failure handling in the agent: notify the caller on dial failure, retry policies, or fallbacks to a human operator.
• If caller ID matters, set sip_number to the original caller’s number on the outbound request.
If you prefer an external API, a hybrid approach can also work:
• Agent requests an authenticated orchestration service to create the SIP participant; the service performs the API call and returns status. This gives centralized logging/control but adds latency and complexity.
If you’d like, I can:
• Provide a short Node or Python snippet showing the agent calling create_sip_participant with wait_until_answered.
• Outline an error-handling flow (retries, notifications, fallback).
• Sketch a hybrid architecture that centralizes logging while keeping the agent in control.
Which option would you like to see next?
Sources: Agents telephony integration | LiveKit Documentation | Agents (Python) | livekit/livekit_composite | DeepWiki | examples/voice_agents | livekit/livekit_composite | DeepWikiearly-butcher-66889
02/28/2026, 6:01 PMtall-airline-16756
02/28/2026, 6:01 PMcreate_sip_participant or tasks such as WarmTransferTask must reference a valid sip_trunk_id so LiveKit knows which trunk and credentials to use for the outbound leg.
Practical notes
• Configure an outbound trunk with your SIP provider or use LiveKit’s phone-number/trunk configuration (where available), and then use that trunk’s ID when making the outbound call.
• Include the sip_trunk_id when calling the API that creates the outbound participant.
• If you need the callee to see the original caller’s number, set the outbound `sip_number`/caller ID appropriately on the outbound request (if your trunk and provider allow that).
• Without a valid trunk, LiveKit cannot initiate or route outbound PSTN calls.
If you’d like, I can:
• Provide a short code snippet showing how to pass sip_trunk_id and sip_number to create_sip_participant.
• Outline common trunk setup checklist items (credentials, caller ID provisioning, trunk testing).
Which would help you next?
Sources: WarmTransferTask | LiveKit Documentation | Agents telephony integration | LiveKit Documentation | Outbound Calling Script | LiveKit Documentationearly-butcher-66889
02/28/2026, 6:40 PMtall-airline-16756
02/28/2026, 6:40 PMcreate_sip_participant from inside your LLM agent — specifically whether the LiveKit API is available through the agent context. Short answer: yes — the agent has access to the LiveKit API via the session/job context (e.g., AgentSession / JobContext), and you can call create_sip_participant directly from your agent code.
How it fits in the agent
• The agent session exposes a JobContext (or similar) that includes authenticated API clients and helpers for controlling the room.
• Use that API client to call create_sip_participant with the sip_trunk_id, destination number, and options such as wait_until_answered.
Minimal example (Python-style pseudocode)
async def transfer_call(job_ctx, phone_number: str):
# job_ctx.api is the LiveKit API client available in the agent context
resp = await job_ctx.api.sip.create_sip_participant(
api.CreateSIPParticipantRequest(
room_name=job_ctx.room.name,
sip_trunk_id="your_sip_trunk_id",
sip_call_to=phone_number,
participant_identity=f"transfer_{phone_number}",
wait_until_answered=True,
sip_number="original_caller_number" # optional: preserve caller ID
)
)
return resp
Key fields to include
• `room_name`: the LiveKit room where the transfer should join.
• `sip_trunk_id`: the outbound trunk ID you configured (required to place outbound PSTN calls).
• `sip_call_to`: the target phone number to dial.
• `participant_identity`: a distinct identity for the new participant so you can track/clean up.
• `wait_until_answered`: recommended so the agent only drops after the call is answered.
• sip_number (optional): set to original caller ID if your trunk/provider allows it.
Practical tips
• Use the API client provided by job_ctx (or AgentSession) rather than instantiating a separate client — it already has the proper credentials and context.
• Keep credentials scoped and stored securely (environment variables / secrets). The agent framework provides the authenticated client so you don’t need to re-authenticate inside the agent code.
• Implement error handling: handle unanswered calls, trunk errors, and timeouts, and notify the caller if the transfer fails.
• After confirming the outbound participant has joined, disconnect the agent from the room so the call continues between the two parties.
If you’d like, I can:
• Provide a Node.js example matching your stack.
• Show a fuller agent function with error handling and caller notification steps.
Which would you prefer?