Skip to main content
Put your number on a Telnyx SIP connection, with LiveKit running your agent. Telnyx carries out the transfer itself, so your agent leaves the call before the caller reads their card. Read Connect your phone system first for how the handoff works and what every setup needs.
Temporary workaround. Telnyx sends calls created by a SIP REFER unencrypted, ignoring the connection’s SRTP setting, and Natural refuses those calls. Until Telnyx fixes this confirmed bug, transfer through a Telnyx SIP subdomain, as in Create the handoff connection. Natural will tell you when the fix ships, and then you:
  1. Transfer to dialUri exactly as returned, without swapping the host.
  2. Delete the handoff connection.

Put your number on a SIP connection

Your Telnyx account must be on a paid tier, because trial accounts refuse unverified callers and can’t place the transfer leg. Your number must be on a SIP connection, not a Call Control or TeXML application (why). Connect an FQDN connection to LiveKit with LiveKit’s Telnyx guide, using LiveKit’s secure trunking steps for TLS, then check these settings: With the API, set these through Update an FQDN connection, Update a phone number with voice settings, and Update an outbound voice profile. Keep SIPREC, media streaming, and transcription off on the number and connection. A connection webhook is fine, since it only reports when calls start, are answered, and end, and where they were transferred.

Create the LiveKit inbound trunk

One inbound trunk takes both new calls and returning callers, so list your number and the return user from your returnTarget.
Media encryption must be SIP_MEDIA_ENCRYPT_ALLOW, not REQUIRE, because Telnyx’s bug also affects the transfer back. Returning callers arrive unencrypted and REQUIRE would drop them, though that leg carries no card data. Add a dispatch rule that sends calls on this trunk to your agent. If you restrict the trunk’s allowed_addresses, allow every Telnyx signaling IP, because Telnyx picks the region per call.

Create the handoff connection (temporary)

Create a second FQDN connection that points at Natural, with a SIP subdomain that only your own connections can call. Leave its webhook empty, and skip the outbound voice profile, which it doesn’t need. Use one handoff connection per environment, each with its own subdomain. With the API, create the connection, then its FQDN:
cURL

Transfer the caller

When the caller is ready to pay, create the voice session with your returnTarget, swap the host in its dialUri for your subdomain, and cold transfer the caller there.
Change only the host and keep the rest of dialUri as returned. If creating the session or the transfer fails, offer the caller the checkout link instead. Your agent leaves the call only once Telnyx accepts the transfer.

Recognize returning callers

When the payment is done, Natural asks Telnyx to transfer the caller to your returnTarget. The caller arrives in a new room, addressed to pay-return instead of your phone number, and LiveKit puts that address in the caller’s sip.trunkPhoneNumber attribute. Use the caller’s own number, in sip.phoneNumber, to find the conversation, and accept the match only if you handed that caller to Natural within the last 30 minutes, the longest a payment call can run, since caller ID alone can be faked.
Before offering anything, read the session’s payment.outcome, and if it’s paid, don’t offer another transfer. If the caller’s number is withheld or matches no conversation, greet them as a new caller.

Why not Call Control or TeXML

A number on a Call Control or TeXML application stays under that application for the whole call. Telnyx’s transfer command and TeXML’s <Dial> bridge the caller to Natural, so your application keeps the caller’s leg while they read their card. On Call Control, Telnyx also sends every key press on that leg to your webhook, card digits included. A Call Control refer hands the transfer to the caller’s phone carrier instead, which refused it or dropped the caller in Natural’s tests.

Test it

Place a test call in Sandbox and run the go-live checks.