For LiveKit and Genesys integration, I want to do ...
# ask-ai
n
For LiveKit and Genesys integration, I want to do the cold call transfer back to Genesys, how to do that
t
Thanks for reaching out, Yuhan. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
You're asking how to perform a cold call transfer from LiveKit back to Genesys. Here’s a concise, actionable path you can use. Prerequisites • Ensure your LiveKit project has an outbound SIP trunk to Genesys and the trunk accepts SIP REFER. • Ensure JWTs used for SIP actions include the
sip.call
grant. • Confirm the destination number/SIP URI is routable in Genesys. How to perform the cold transfer 1. Call the server-side API
transfer_sip_participant
(also shown as
TransferSIPParticipant
in SDKs). 2. Pass the current room name, the caller/participant identity, and the destination as either an E.164 number (
tel:+15105550123
) or a SIP URI (
<sip:user@genesys.com>
). Optionally set
play_dialtone
if you want a dial tone to the caller while connecting. Example (Python):
Copy code
await livekit_api.sip.transfer_sip_participant(
  api.TransferSIPParticipantRequest(
    room_name="current-room-name",
    participant_identity="caller-identity",
    transfer_to="tel:+15105550123",
    play_dialtone=False
  )
)
Example (Node.js):
Copy code
await sipClient.transferSipParticipant(
  'current-room-name',
  'caller-identity',
  'tel:+15105550123',
  { playDialtone: false }
);
Verification and common issues • Make sure Genesys accepts REFER requests and the SIP trunk allows transfers. • If you see SIP errors: ◦ 408 Request Timeout — check network connectivity and SIP reachability. ◦ 403 Forbidden — verify JWT permissions include
sip.call
. • If using a SIP URI, ensure SRTP/TLS and DNS/resolution settings are compatible between LiveKit and Genesys. Notes • Cold transfer hands the caller off immediately; the LiveKit agent session ends after transfer. •
transfer_to
can be
tel:+...
or
sip:...
depending on your Genesys routing. If you want, tell me: • the SDK/language you’re using (Node/Python/other), and • whether you’ll transfer to a phone number or a SIP URI, and I’ll provide a tailored code snippet or checklist for Genesys trunk settings. Sources: SIP APIs | LiveKit docs | SIP troubleshooting guide | LiveKit docs | Agents telephony integration | LiveKit docs
Thanks — I understand your flow: caller -> Genesys -> Genesys adds LiveKit agent via outbound SIP trunk -> after caller asks for a real human, LiveKit should transfer the call back to another Genesys number. Here’s how to implement that. 1) Prerequisites to verify • LiveKit has an outbound SIP trunk to Genesys that accepts incoming REFER requests. • JWTs used for SIP operations include the
sip.call
grant. • The Genesys destination number or SIP URI you’ll transfer to is routable on that Genesys trunk. 2) Implementation overview • From your LiveKit server (not the browser client), call the server-side API to transfer the SIP participant:
transfer_sip_participant
(aka
TransferSIPParticipant
). • Provide the LiveKit room name, the LiveKit participant identity that represents the caller, and the Genesys destination as
tel:+E.164
or
sip:uri
. • Optionally set
play_dialtone
if you want the caller to hear a dial tone while the transfer completes. 3) Example (choose your language) • Python:
Copy code
await livekit_api.sip.transfer_sip_participant(
  api.TransferSIPParticipantRequest(
    room_name="room-name",
    participant_identity="caller-identity",
    transfer_to="tel:+15105550123",
    play_dialtone=False
  )
)
• Node.js:
Copy code
await sipClient.transferSipParticipant(
  'room-name',
  'caller-identity',
  'tel:+15105550123',
  { playDialtone: false }
);
4) Genesys trunk settings & compatibility • Ensure the Genesys SIP trunk will accept and honor SIP REFER from LiveKit. • Confirm SRTP/TLS and codec compatibility and that the destination number/SIP URI resolves within Genesys. • If Genesys requires any special headers or authentication for transfers, ensure LiveKit’s SIP trunk sends them or Genesys is configured to accept the REFER as-is. 5) Common failure modes to check • 408 Timeout: network/SIP reachability from LiveKit to Genesys destination. • 403 Forbidden: JWT missing
sip.call
grant. • Call doesn't connect: destination not routable or Genesys rejecting REFER—check trunk logs on the Genesys side. If you’d like, tell me: • which SDK/language you want the final snippet in (Node/Python/other), and • whether you’ll transfer to a phone number (
tel:+...
) or a SIP URI, and I’ll give a ready-to-drop-in code sample and a short Genesys-checklist for trunk settings.
n
the LiveKit should have inbound trunk instead outbaound trunk so that it can take the call from Genesys?
t
Good question — I’ll clarify how trunks should be arranged for your flow (Genesys -> LiveKit agent join -> transfer back to Genesys). Short answer • LiveKit needs an inbound-capable SIP trunk (or a trunk that accepts incoming SIP INVITEs) so Genesys can call into LiveKit and add the LiveKit agent as an external joiner. • To transfer the call back to another Genesys number, LiveKit needs the ability to send a SIP REFER to Genesys — this can be the same trunk if it supports both incoming calls and REFERs, or a separate outbound-capable trunk to Genesys. The key is that the trunk you use for the transfer must accept REFERs and route the destination number within Genesys. Why this setup works • Inbound trunk: allows Genesys to place the initial call into LiveKit (INVITE → LiveKit). • REFER support / outbound capability: allows LiveKit to perform a cold transfer by issuing a SIP REFER to Genesys with the target
tel:
or
sip:
destination. Genesys must accept and handle that REFER (or the trunk must be able to forward the call into Genesys). What to verify in your Genesys / trunk config • The trunk accepts incoming INVITEs from Genesys (for external join). • The trunk accepts SIP REFER requests from LiveKit and will route the REFER’s target within Genesys. • Authentication, TLS/SRTP, and codec compatibility are aligned both directions. • Any required headers or transfer policies in Genesys are allowed for REFER-based transfers. Recommended options • Easiest: Use one trunk between LiveKit and Genesys that supports both inbound calls and REFER transfers. • Alternative: Use an inbound trunk to receive the join, and a separate outbound trunk from LiveKit to Genesys for transfers — ensure both trunks are authorized and compatible. If you want, tell me: • whether you already have a single trunk between LiveKit and Genesys or separate trunks, and • whether Genesys requires special headers/authentication on REFERs, and I’ll provide a short checklist of configuration items and a sample transfer call flow.
n
I want to have a single trunk between LiveKit and Genesys
t
Thanks — since you want a single trunk, here's a concise checklist and the exact steps to make the flow work (Genesys → LiveKit agent via inbound INVITE, then LiveKit cold-transfers back to Genesys using the same trunk). What the single trunk must support • Accept incoming INVITEs from Genesys (so Genesys can add LiveKit as an external joiner). • Accept and route SIP REFER requests from LiveKit (for cold transfers). • Support the same transport/security (TLS or TCP) and media (SRTP if used) both directions. • Preserve or allow required SIP headers (From/To/Refer-To, any Genesys-required header). • Use codecs common to both sides (e.g., OPUS/PCMU) and negotiate correctly. Configuration checklist • Trunk direction: Configure the trunk as bidirectional (allow inbound INVITE and inbound REFER handling). • REFER handling: Ensure the trunk accepts REFER from LiveKit and forwards the REFER target into Genesys routing. • Authentication & trust: Ensure LiveKit IPs/credentials are authorized on the trunk; configure TLS certs if using TLS. • Media: Enable SRTP (or disable if not required) consistently on both LiveKit and Genesys. • Header/policy: Allow or map any Genesys-required custom headers; don’t strip Refer-To or Replaces headers. • Routing: Confirm Genesys will route the REFER’s
tel:+E.164
or
sip:
URI target internally to the intended Genesys endpoint. • Logging/test hooks: Enable SIP tracing on the trunk to validate INVITE, REFER, and resulting INVITEs from Genesys. Call flow summary (single-trunk) 1. Caller calls Genesys customer-facing number. 2. Genesys places an outbound INVITE to LiveKit via the single trunk to add the LiveKit agent (LiveKit receives INVITE → agent joins room). 3. Agent decides to transfer back to Genesys. 4. LiveKit (server-side) issues
transfer_sip_participant
which sends a SIP REFER over the same trunk to Genesys with
Refer-To: tel:+X
or
sip:agent@genesys
. 5. Genesys receives the REFER and performs the transfer by placing a new call to the Refer-To target inside Genesys routing; the original LiveKit session ends. Code step (server-side) • Use the server-side
transfer_sip_participant
API and set
transfer_to
to the Genesys destination (E.164 or SIP URI). Example patterns are identical to earlier snippets: Python:
Copy code
await livekit_api.sip.transfer_sip_participant(
  api.TransferSIPParticipantRequest(
    room_name="room-name",
    participant_identity="caller-identity",
    transfer_to="tel:+15105550123",
    play_dialtone=False
  )
)
Node.js:
Copy code
await sipClient.transferSipParticipant(
  'room-name',
  'caller-identity',
  'tel:+15105550123',
  { playDialtone: false }
);
Troubleshooting hints • If Genesys never places the final call after REFER: check that Genesys accepts REFER and that
Refer-To
is routable inside Genesys. • If you see 403 on transfer: ensure JWT includes
sip.call
grant and trunk auth allows REFER. • If media fails after transfer: verify SRTP/TLS and codec agreement for the new call. If you want, I can: • Provide a short Genesys-side checklist of exact headers/flags to allow (if you tell me whether Genesys expects any custom headers), or • Generate a complete test plan with SIP traces to validate INVITE → REFER → final INVITE on the single trunk. Which would you prefer?
n
I see iveKit SIP transfer failed with TwirpError (code=deadline_exceeded, message=TwirpError(code=deadline_exceeded, message=twirp error unknown: request timed out, status=408), transfer_to=sip:+xxxxxx@xxxxx). I've already enabled the REFER in Genesys trunk
t
Thanks — I see the transfer timed out with TwirpError 408 even though REFER is enabled on the Genesys trunk. I’ll help you troubleshoot. Quick checklist to verify (please confirm each): • Is
transfer_to
a
sip:
URI or
tel:
E.164? Share which one you used. • Can Genesys show an incoming REFER in its SIP logs for this call? (Do you see the REFER arrive or not?) • Are LiveKit’s SIP trunk IPs/credentials authorized on the Genesys trunk and allowed to issue REFERs? • Are there any Genesys policies requiring extra headers, authentication, or allowed referrers for REFERs? • Any firewalls/NAT between LiveKit and Genesys that could block the REFER or the REFER response? Steps to run now 1. Verify SIP message exchange: ◦ Check LiveKit SIP traces to confirm the REFER was sent and note the timestamp. ◦ Check Genesys SIP logs for that timestamp to see if REFER arrived and whether Genesys responded (e.g., 202/405/403 or no response). 1. Validate
transfer_to
value: ◦ If
sip:...
, ensure DNS/SRTP/TLS and user@domain are resolvable and routable in Genesys. ◦ If
tel:+...
, ensure Genesys will accept and route that number from the trunk. 1. Confirm trunk accepts REFER: ◦ Even when REFER is enabled, confirm Genesys will accept REFERs from this peer and will not drop/require extra headers. 1. Check auth/headers: ◦ If Genesys requires specific authentication or headers on REFER, ensure LiveKit trunk config supplies them. 1. Network checks: ◦ Confirm no firewall/NAT drops packets and that return responses can reach LiveKit. 1. Retry with logs: ◦ Retry the transfer while capturing SIP traces on both LiveKit and Genesys; compare timestamps to see where the response is missing. If you can, share: • whether
transfer_to
was
sip:
or
tel:
, • a timestamp (UTC) of a failed transfer attempt, • the SIP call-id or room name used (if available), and I’ll point to the exact SIP messages to look for and recommend next checks based on what the logs show. Sources: Call forwarding | LiveKit docs | SIP troubleshooting guide | LiveKit docs
n
I see this transferStatus: "STS_TRANSFER_FAILED" error: "transaction failed to complete (0 intermediate responses)"
t
Thanks — I see the transfer returned
STS_TRANSFER_FAILED
with "transaction failed to complete (0 intermediate responses)". That means LiveKit sent the REFER but received no provisional (1xx) or final responses from Genesys before timing out. Let’s focus on the quickest checks to find where it’s getting dropped. Please confirm these and run the checks below: 1) What
transfer_to
did you use?
sip:
URI or
tel:
number? 2) Provide a UTC timestamp (and call-id or LiveKit room name) for a failed attempt so we can align logs. Immediate checks to run now • LiveKit SIP trace: confirm the REFER was sent and capture the exact SIP headers (Call-ID, From, To, Refer-To, Via, Contact, CSeq). Note timestamp. • Genesys SIP trace: search that timestamp/Call-ID for the incoming REFER. Do you see it arrive? If not, the REFER is being dropped en route (network/trunk auth). • If Genesys sees the REFER but sends no 1xx/2xx/4xx: inspect Genesys routing/policies — it may silently discard REFERs that lack expected headers or authentication. • Trunk peer auth/allowed methods: ensure the trunk allows REFER from LiveKit’s peer (IP/credentials) and does not require extra headers (X- or Proxy- headers) or a specific Referrer header. • DNS/URI and transport: if
sip:
ensure the domain resolves and transport/TLS/SRTP match; if
tel:
ensure Genesys will route that E.164 via the same trunk. • Firewall/NAT: verify return path for SIP responses is open so provisional responses can reach LiveKit. If you can paste (sanitized) the REFER SIP request headers or the LiveKit trace snippet and the Genesys trace around the same timestamp, I’ll point to the exact missing piece (e.g., missing Via response, authentication reject, or network drop) and next steps to fix it.
Thanks — you tried both
sip:
and
tel:
and gave Call-ID SCL_EwzUnTntFrwT. I’ll focus on steps to locate why no responses arrived and what to check next. Please run these checks and share results (or paste sanitized traces): 1) Confirm LiveKit sent the REFER • Pull LiveKit SIP trace for Call-ID SCL_EwzUnTntFrwT and confirm a REFER was sent. Copy the REFER request headers:
Call-ID
,
CSeq
,
From
,
To
,
Refer-To
,
Via
,
Contact
. Note the timestamp. 2) Check Genesys for incoming REFER • Search Genesys SIP logs for that same Call-ID or timestamp. Do you see the REFER arrive? If yes, paste the Genesys 1xx/2xx/4xx response (if any). If no, the REFER is being dropped between LiveKit and Genesys. 3) If REFER did not arrive at Genesys — network/trunk auth • Verify LiveKit IPs/peer and credentials are authorized on the Genesys trunk. • Check firewalls/NAT between LiveKit and Genesys that could block packets or block responses to the Via/Contact addresses. • Ensure DNS for any
sip:
domain resolves from Genesys and LiveKit as expected. 4) If REFER arrived but Genesys sent no provisional/final response • Inspect Genesys routing/policies for REFER handling — confirm the trunk allows REFER and doesn’t silently discard due to missing headers or disallowed methods. • Check if Genesys expects extra headers (custom or Proxy-Authorization) on REFERs; if so, ensure trunk or LiveKit can supply them. 5) Validate
Refer-To
formatting • For SIP URI:
Refer-To: <sip:user@domain>
with correct domain and transport (sip: vs sips:). • For tel:
Refer-To: <tel:+E.164>
and ensure Genesys will route that number via the trunk. • If you used
sip:+xxxxxx@xxxxx
that format can be unusual — prefer
sip:user@domain
or
tel:+E.164
. 6) Retry with simultaneous tracing • While retrying transfer, capture LiveKit trace and Genesys trace for the same second-range. Compare timestamps to see where the handshake stops. What to share here for next steps • The LiveKit REFER request headers (sanitized). • Whether Genesys log shows the REFER and any response (sanitized). • Timestamp (UTC) of the failed transfer attempt. With those, I’ll point to the exact missing SIP message or header and recommend the fix (trunk header mapping, auth, DNS, or network rule).
n
to do the SIP REFER from LiveKit to Genesys, do I need an outbound trunk set up in LiveKit
t
Short answer: Yes — LiveKit must be able to send the SIP REFER out to Genesys, so you need outbound-capable signaling on the trunk used for transfers. That can be: • A single bidirectional trunk that accepts inbound INVITEs from Genesys and also allows LiveKit to send outbound REFERs/INVITEs back to Genesys (recommended), or • A separate outbound trunk from LiveKit to Genesys dedicated for transfers. What to ensure on that trunk • It accepts and routes SIP REFER requests from LiveKit. • LiveKit’s peer IP/credentials are authorized to send outbound requests (including REFER). • Transport, TLS/SRTP, and codecs match both sides. • Trunk/policy does not strip Refer-To or required headers and allows the REFER method. • DNS/URI resolution for any
sip:
targets works from both sides. If you want, tell me whether you currently have one bidirectional trunk or separate trunks and I’ll give the exact trunk settings and a quick test plan to validate REFERs.
n
how do I know if my LiveKit trunk is bidirectional? In the LiveKit Cloud SIP trunks section, the Inbound and Outbound trunks are seperate
t
Good question — I’ll clarify how to check if your LiveKit trunk is bidirectional and what to do in the Cloud UI where Inbound and Outbound trunks appear separate. Short answer • If the LiveKit Cloud shows separate Inbound and Outbound trunk entries, that means you currently have distinct trunks configured. A true bidirectional trunk must be configured to accept inbound INVITEs and also allow LiveKit to send outbound SIP requests (REFER/INVITE) over the same peer; in the Cloud UI this may appear as a single trunk configured with both inbound and outbound settings, or as two entries that are paired to the same remote peer and credentials. How to verify bidirectionality 1. Console / Trunk details ◦ Open the SIP trunk entry in the LiveKit Cloud UI. Check whether the trunk entry lists both inbound settings (listening/receive rules) and outbound credentials/peer address. If one entry shows both, it’s bidirectional. 1. Check peer/credentials ◦ If you have separate Inbound and Outbound trunks, check whether they point to the same remote IP/domain and use the same credentials. If they do and the remote trunk accepts both directions, they can function as a single bidirectional link, but they are still managed as separate trunks in the UI. 1. Test behavior ◦ Inbound test: Have Genesys place an INVITE to LiveKit and confirm LiveKit receives the call. ◦ Outbound test: From LiveKit, place an outbound INVITE or send a REFER to the same Genesys peer and confirm Genesys receives and responds. ◦ If both tests succeed over the same remote peer/address, the linkage is effectively bidirectional. 1. API / Trunk configuration (if available) ◦ Inspect the trunk configuration via the LiveKit API (or Cloud UI export) for fields indicating permitted methods and allowed directions. Look for settings that enable outbound routing and allowed SIP methods (including REFER). If you find separate inbound/outbound trunks and want a single trunk • Preferred: Configure a single trunk (or a single peer entry) on the LiveKit side that includes both inbound accept rules and outbound peer/credential configuration, and ensure Genesys is configured to accept both inbound INVITEs and REFERs from that same peer. • Alternative: Keep separate inbound and outbound trunks but ensure they point to the same remote peer and that Genesys treats them as the same trusted peer for transfers (authorization, allowed methods, headers). Quick checklist to validate now • Confirm the remote peer IP/domain and credentials for both trunks — are they identical? • Run an inbound INVITE test and an outbound REFER/INVITE test to the same peer while capturing SIP traces on both sides. • Ensure the trunk allows the REFER method and does not strip Refer-To/required headers. If you tell me: • whether the Inbound and Outbound trunks show the same remote IP/domain and credentials, and • you can run a quick outbound test (REFER or INVITE) and share the timestamp, I’ll give the exact SIP messages to look for and a recommended change (single trunk config or pairing steps) based on what you see.