loud-postman-20421
09/17/2025, 4:53 PMtall-airline-16756
09/17/2025, 4:53 PMtall-airline-16756
09/17/2025, 4:54 PMTransferSIPParticipant API to initiate the transfer. You can set the ringing_timeout parameter to 15 seconds so the call stops ringing automatically after that time.
• Once the transfer starts, the SIP participant will leave the LiveKit room. This naturally stops the agent from listening and generating speech, as the session ends when the participant leaves.
Here's a simple example in Python to guide you:
from livekit import api
from google.protobuf.duration_pb2 import Duration
await ctx.api.sip.transfer_sip_participant(
api.TransferSIPParticipantRequest(
room_name=ctx.room.name,
participant_identity=participant_identity,
transfer_to="tel:+15105550123",
ringing_timeout=Duration(seconds=15)
)
)
Also, please make sure your SIP trunk supports SIP REFER for transfers. If you're using Twilio, you'll want to enable PSTN Transfer and set transfer-mode to enable-all.
If you have any questions or need a hand with anything else, just let me know—I'm here to help!
Sources: Agents telephony integration | LiveKit Docs | Transferring calls | LiveKit Docs | livekit-agents/livekit/agents/job.py | livekit-api/livekit/api/sip_service.pyloud-postman-20421
09/17/2025, 4:57 PMtall-airline-16756
09/17/2025, 4:57 PMTransferSIPParticipant API! You can check it out on the official LiveKit SIP APIs page here: TransferSIPParticipant Documentation.
This page covers all the details you'll need, including required parameters, optional settings, and authentication requirements. If you have any questions or need a hand with anything else, just let me know—I'm here for you!
Sources: SIP APIs | LiveKit Docs | Transferring calls | LiveKit Docsloud-postman-20421
09/17/2025, 4:58 PMtall-airline-16756
09/17/2025, 4:58 PMTransferSIPParticipant API does indeed support setting a ringing timeout through the ringing_timeout field in the TransferSIPParticipantRequest. This lets you specify how long (for example, 15 seconds) the transfer destination has to answer before the transfer is considered failed.
Here’s a friendly example to show you how to include it:
from google.protobuf.duration_pb2 import Duration
await ctx.api.sip.transfer_sip_participant(
api.TransferSIPParticipantRequest(
room_name="my-room",
participant_identity="sip-participant",
transfer_to="<sip:1234@example.com>",
ringing_timeout=Duration(seconds=15) # 15-second timeout
)
)
If you have any more questions or need a hand with this, just let me know—I’m here to help!
Sources: rpc/sip.go | pkg/service/sip.goloud-postman-20421
09/17/2025, 5:00 PMtall-airline-16756
09/17/2025, 5:01 PMTransferSIPParticipant operation can be a bit tricky. When the ringing timeout is reached during this process, the transfer attempt doesn’t go through, but don’t worry—the original SIP participant stays connected in the current call. So, there’s no need to reconnect since they’re never actually disconnected during the transfer.
If the transfer doesn’t succeed because of a timeout, the original call will continue just as it was. Please feel free to reach out if you’d like me to explain anything further or if you have any other questions—I’m here to help!
Sources: pkg/sip/service.go | SIP troubleshooting guide | LiveKit Docsloud-postman-20421
09/17/2025, 5:01 PMtall-airline-16756
09/17/2025, 5:02 PMloud-postman-20421
09/17/2025, 5:03 PM{"message": "Failed to transfer call: Protocol message TransferSIPParticipantRequest has no \"set_timeout_seconds\" field.\loud-postman-20421
09/17/2025, 5:03 PMtall-airline-16756
09/17/2025, 5:03 PMset_timeout_seconds field isn’t actually part of the TransferSIPParticipantRequest. No worries though! To manage timeouts, you can try these approaches:
• Ringing Timeout: You can use the ringing_timeout field in your request to set how long the system should wait for the transferred call to be answered—say, 15 seconds as an example.
• Context Deadline: Another way is to pass a context with a custom timeout (like context.WithTimeout in Go or something similar in other languages) when you call the API. This way, you control how long your client waits for the operation to finish.
If you’d like, I’m here to help you set this up or answer any questions you have!
Sources: rpc/sip.pb.go | livekit-protocol/src/livekit.rs | sipclient.go | pkg/service/sip.gotall-airline-16756
09/17/2025, 5:04 PMloud-postman-20421
09/17/2025, 6:21 PMtall-airline-16756
09/17/2025, 6:22 PMTransferSIPParticipant times out, so let me guide you through a friendly approach to manage this smoothly:
• Set a Context Deadline: You can use a custom timeout (like context.WithTimeout in Go or something similar) to decide how long your client should wait for the operation to finish.
• Catch Timeout Errors: It’s helpful to detect specific timeout errors (such as 408 Request Timeout) so you can respond accordingly—maybe notify the user or even try the transfer again.
• Use Ringing Timeout: Adjust the ringing_timeout field in your request to control how long the system waits for the destination to pick up.
Here’s a simple example in Python to get you started:
try:
await ctx.api.sip.transfer_sip_participant(
api.TransferSIPParticipantRequest(
room_name="my-room",
participant_identity="sip-participant",
transfer_to="tel:+18003310500",
ringing_timeout=Duration(seconds=15)
)
)
except Exception as e:
if "408" in str(e):
await ctx.room.local_participant.publish_data("Call transfer timed out. Connecting you to support.")
else:
logger.error(f"Unexpected error: {e}")
If you’d like, I’m here to help you implement this or answer any questions along the way!
Sources: pkg/sip/service.go | Making calls using SIP | LiveKit Docs | examples/voice_agents/error_callback.py | pkg/service/sip.go | sipclient.goloud-postman-20421
09/17/2025, 6:23 PMtall-airline-16756
09/17/2025, 6:24 PMTransferSIPParticipant, a great approach is to run the transfer as a background task and manage interruptions gracefully. Here’s a friendly step-by-step guide:
1. Run the transfer as a background task: You can use asyncio.ensure_future() to start the transfer without blocking the main thread, keeping things smooth.
2. Handle interruptions: By using run_ctx.speech_handle.wait_if_not_interrupted(), you wait for the task to finish unless the user interrupts it.
3. Return a response: It’s helpful to provide a fallback message if the transfer times out or gets interrupted, so users stay informed.
Here’s an example to illustrate this:
@function_tool
async def transfer_sip_participant_tool(self, participant_identity, transfer_to, run_ctx):
transfer_task = asyncio.ensure_future(
self.api.sip.transfer_sip_participant(
api.TransferSIPParticipantRequest(
room_name=run_ctx.room.name,
participant_identity=participant_identity,
transfer_to=transfer_to,
play_dialtone=True,
)
)
)
await run_ctx.speech_handle.wait_if_not_interrupted([transfer_task])
if run_ctx.speech_handle.interrupted:
transfer_task.cancel()
return "Transfer was interrupted."
return "Call transferred successfully."
This way, the LLM tool call won’t block forever and you’ll handle any timeouts or interruptions smoothly. If you have any questions or want to explore this further, just let me know—I’m here to help!
Sources: examples/voice_agents/long_running_function.py | sipclient.go | packages/livekit-server-sdk/src/SipClient.ts | Making calls using SIP | LiveKit Docs | sip-refer/agent.py