This message was deleted.
# ask-ai
s
This message was deleted.
t
Thanks for reaching out, Arti. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
The SIP REFER failure with code 603 indicates a global decline, meaning the transfer destination rejected the call globally and is unavailable anywhere in the network. This can happen due to: • Invalid Transfer Destination: The destination number might be malformed, non-existent, or blocked by the SIP provider. • SIP Trunk Configuration Issues: Restrictions or misconfigurations in your SIP trunk could prevent the transfer. • Network and Protocol Issues: Problems like NAT traversal, firewall rules, or transport protocol mismatches can interfere with SIP signaling. To troubleshoot: 1. Verify the format of the REFER request, ensuring the SIP URI is correct. 2. Check your SIP trunk configuration, including provider capabilities and number formatting requirements. 3. Ensure proper network configuration, including open SIP signaling ports and correct NAT traversal settings. 4. Test with different destinations to isolate the issue. If the issue persists, monitoring the SIP signaling process can help identify where the failure occurs. Let me know if you need further assistance with any of these steps. Sources: rpc/sip.psrpc.go | pkg/sip/outbound.go
a
but then why would this one succeed when its to the same number? Aug 06 120851 ip-172-31-33-255 livekit-server[68757]: 2025-08-06T120851.168Z INFO livekit.api service/twirp.go:128 API SIP.TransferSIPParticipant {"service": "SIP", "method": "TransferSIPParticipant", "room": "call-_+447949410617_jAcoQCydopHw", "participant": "sip_+447949410617", "transferTo": "sip:+441162123399@ss012a.hostcommservers.co.uk;user=phone", "playDialtone": true, "room": "call-_+447949410617_jAcoQCydopHw", "participant": "sip_+447949410617", "duration": "9.418776ms", "status": "200"}
t
Hey there! When you see a SIP REFER to the same number happening right after a previous failure with code 603, it could be due to a few temporary or situational reasons. Here are some possibilities to consider: • Temporary Network or Provider Issues: Sometimes, the first failure happens because of a brief hiccup with the SIP provider or network, which might have cleared up by the time the second attempt was made. • Participant Context: The state or context of the participant (like whether they’re actively on a call or have certain permissions) can change and affect how the transfer goes. • Timing or Load: The SIP provider might have been a bit overloaded or had routing issues during that first try. • Configuration Changes: Any tweaks made to the SIP trunk or provider settings between the two attempts could also play a role. If you want to dig deeper, a good next step is to compare the SIP signaling logs from both attempts to spot any differences in the REFER requests or responses. And hey, if you’d like a hand going through those logs or figuring out what’s going on, just let me know—I’m here to help!
a
Where would I find these SIP logs?
t
Hey there! Are you using LiveKit Cloud or running a self-hosted LiveKit setup? If it’s self-hosted, could you let me know how you’ve deployed it (like Docker, Kubernetes, or maybe a direct binary installation)? That way, I can point you to exactly where the SIP signaling logs are. Thanks! Sources: pkg/sip/protocol_test.go | CHANGELOG.md
a
Self hosted Livekit worker - This is installed on the server we build for clients and runs as a system service. Livekit SIP - Runs as a standalone service within a Docker container. This is also installed on the server
t
For your self-hosted setup, here’s how you can check out the SIP signaling logs: • LiveKit SIP Service (Docker Container): Just run
docker logs <container-name>
to see the logs for the SIP service. Don’t forget to swap out
<container-name>
with the actual name of your SIP service container. • LiveKit Worker (System Service): You can find the system logs for the LiveKit worker service usually in
/var/log/
or by using
journalctl -u <service-name>
. Again, replace
<service-name>
with your LiveKit worker service’s name. Try searching the logs for keywords like "REFER," "NOTIFY," or the participant and room IDs involved in the transfer. If you need a hand with accessing or making sense of these logs, just let me know—I’m here to help!
a
Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/livekit-server/pkg/service.(*SIPService).TransferSIPParticipant Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/livekit-server@v1.8.4/pkg/service/sip.go:526 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/livekit.(*sIPServer).serveTransferSIPParticipantJSON.func1.1 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/livekit/livekit_sip.twirp.go:3723 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/utils/xtwirp.DefaultServerOptions.ServerPassErrorDetails.func2.1 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/utils/xtwirp/errors.go:165 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/utils/xtwirp.DefaultServerOptions.ServerPassTimeout.func1.1 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/utils/xtwirp/timeout.go:50 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/livekit.(*sIPServer).serveTransferSIPParticipantJSON.func1 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/livekit/livekit_sip.twirp.go:3725 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/livekit.(*sIPServer).serveTransferSIPParticipantJSON.func2 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/livekit/livekit_sip.twirp.go:3741 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/livekit.(*sIPServer).serveTransferSIPParticipantJSON Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/livekit/livekit_sip.twirp.go:3742 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/livekit.(*sIPServer).serveTransferSIPParticipant Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/livekit/livekit_sip.twirp.go:3682 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/livekit.(*sIPServer).ServeHTTP Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/livekit/livekit_sip.twirp.go:1505 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: github.com/livekit/protocol/utils/xtwirp.PassHeadersHandler.func1 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /home/runner/go/pkg/mod/github.com/livekit/protocol@v1.34.0/utils/xtwirp/headers.go:36 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: net/http.HandlerFunc.ServeHTTP Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: /opt/hostedtoolcache/go/1.23.6/x64/src/net/http/server.go:2220 Aug 21 154904 ip-172-31-33-255 livekit-server[2265]: net/http.(*ServeMux).ServeHTTP
t
Let's walk through how to debug the SIP REFER issue using the logs you shared. Here are some key steps to keep in mind: • Check REFER Request Validity: Make sure the REFER request has all the right headers, like a valid
Refer-To
URI, the correct CSeq sequence number, and valid contact headers. • Monitor NOTIFY Sequence: Keep an eye out for NOTIFY messages in the logs—they’ll help you track how the transfer is going. These messages tell you if the transfer is in progress (100-199), successful (200), or if it ran into trouble (4xx/5xx). • Interpret Status Codes: Some common failure codes are 403 (Forbidden), 408 (Request Timeout), and 404 (Not Found). These usually hint at issues like authentication problems, network hiccups, or invalid destinations. • Check for TLS Limitations: Just a heads-up—SIP REFER doesn’t work over TLS. So if your SIP trunk uses TLS, that could be why transfers aren’t happening. • Validate SIP Provider Configuration: It’s a good idea to double-check with your SIP provider that REFER transfers are actually enabled and supported on your account. Try searching the logs for keywords like "REFER," "NOTIFY," and those status codes to help zero in on the problem. If you want, I’m here to help you make sense of specific log entries or figure out what to do next! Sources: test/lktest/sip.go | SIP troubleshooting guide | LiveKit Docs | Secure trunking | LiveKit Docs
Thanks for reaching out! I want to reassure you that there haven’t been any recent changes to the SIP REFER functionality in LiveKit. You can still transfer calls to another phone number or SIP endpoint using the
TransferSIPParticipant
API. One thing to keep in mind is that SIP REFER isn’t supported when using TLS for secure trunking, so if TLS is enabled in your setup, that might be causing some hiccups. If you’re seeing the 603 error, it usually means the transfer destination is globally declining the call. This can happen for a few reasons, such as: • Invalid or blocked transfer destination • Provider restrictions or configuration issues • Network or protocol mismatches Please don’t hesitate to reach out if you’d like help troubleshooting this or if you want me to take a closer look at your configuration. I’m here to help! Sources: Docs::Telephony | SIP overview | LiveKit Docs | Docs::Telephony | pkg/sip/inbound.go | CHANGELOG.md
a
can you see anything wrong with this? import z from 'zod'; import { llm } from '@livekit/agents'; import { sip } from '../clients/sip.js'; import type configSchema from '../config.js'; import { type CallUserData } from '../call-user-data.js'; type SIPContact = z.infer<typeof configSchema.shape.departmentContacts.element>; async function doColdTransfer(contact: SIPContact, userData: CallUserData) { const sipTrunkId = userData.persona?.sipTrunkId ?? userData.config.sipTrunkId; if (!sipTrunkId) return `Unable to transfer to ${contact.departmentName} because the no SIP trunk was found.`; if (!userData.roomName) return `Unable to transfer to ${contact.departmentName} because the session room was not found.`; if (!userData.participantSIPPhone) return `Unable to transfer to ${contact.departmentName} because the customer is not using a phone.`; try { //const contactSIPRecipient = `sip:+${contact.number}@a911ndn7bzk.sip.livekit.cloud;user=phone`; //const contactSIPRecipient = `tel:+${contact.number}`; //const contactSIPRecipient = `sip:+${contact.number}@cxc-live-kit.pstn.twilio.com;user=phone`; //const contactSIPRecipient = `tel:+${contact.number}@ss005a.hostcommservers.co.uk;user=phone`; //const contactSIPRecipient = `sip:+${contact.number}@ss012a.hostcommservers.co.uk;user=phone`; //const contactSIPRecipient = `sip:+${contact.number}@${process.env.SIP_TRANSFER_SERVER};user=phone`; const contactSIPRecipient = `tel:+${contact.number}@${process.env.SIP_TRANSFER_SERVER};user=phone`; console.log(
:phone: Cold Transfer "${userData.participantIdentity}" to: ${contactSIPRecipient}
); await sip.transferSipParticipant(userData.roomName, userData.participantIdentity, contactSIPRecipient, { //headers: {}, playDialtone: true, }); return `Calling ${contact.departmentName} now.`; } catch (error) { console.log(
Error dialling contact "${contact.departmentName}"
, error); } return `Error dialling contact`; } // one tool to rule them all. export function dialContactCombined(userData: CallUserData): Record<string, llm.Tool> { const contacts = userData.persona?.departmentContacts ?? userData.config.departmentContacts ?? []; return { dialContact: llm.tool({ description:
Copy code
Called when the user asks to be transferred or wants assistance from a specific contact

Here is a list of available contacts: ${Object.keys(contacts).join(', ')}
, parameters: z.object({ contactName: z.string().describe('The name of the contact to be called'), }), execute: async ({ contactName }, { ctx }) => { console.debug(
:wrench: Executing dialContact function - User asked to be transferred to "${contactName}"
,); const contact = contacts?.find(contact => contact.departmentName === contactName); const userData = ctx.userData as CallUserData; if (!contact) return `No number found for contact: ${contactName}`; return doColdTransfer(contact, userData); }, }), }; } // or a tool for each contact. export function dialContactSeparate(userData: CallUserData): Record<string, llm.Tool> { const contacts = userData.persona?.departmentContacts ?? userData.config.departmentContacts ?? []; const toolName = (contact: SIPContact) => `dialContact-${contact.departmentName.replace(/[^a-zA-Z0-9]+/g, '-')}`; return Object.assign({}, ...contacts.map(contact => ({ [toolName(contact)]: llm.tool({ description:
Called when the user asks to be transferred or wants assistance from ${contact.departmentName}.
, //parameters: z.object({}), execute: async ({}, { ctx, }) => { console.debug(
:wrench: Executing dialContact function - User asked to be transferred to "${contact.departmentName}"
,); const userData = ctx.userData as CallUserData; return doColdTransfer(contact, userData); }, }), }))); }
t
Thanks for sharing your code! Let’s walk through a few areas together that might be causing some hiccups with the SIP REFER implementation: • SIP URI Format: It’s important to double-check that your
contactSIPRecipient
is formatted just right. For example, something like
tel:+number@domain;user=phone
or
sip:+number@domain;user=phone
should align with what your SIP provider expects. • SIP Trunk Configuration: Make sure the SIP trunk you’re using (
sipTrunkId
) has call transfer enabled and the right permissions set up for the destination. • Call State: The call needs to be active and established before you start the transfer. Trying to transfer on calls that aren’t fully established will usually cause it to fail. • Provider-Specific Requirements: Some providers, like Twilio or Telnyx, have their own specific settings to get SIP REFER working smoothly. It’s worth confirming those are configured correctly. • Environment Variables: Take a moment to check that
process.env.SIP_TRANSFER_SERVER
is correctly set and points to a valid domain. Also, keeping an eye on the logs for NOTIFY responses can really help you see how the transfer is progressing and spot any errors along the way. If you’d like, I’m here to help you dig into these checks or go through the logs together. Just let me know! Sources: Docs::Telephony | SIP troubleshooting guide | LiveKit Docs | Transferring calls | LiveKit Docs | SIP overview | LiveKit Docs | pkg/sip/outbound.go