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 yourreturnTarget.
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 yourreturnTarget, swap the host in its dialUri for your subdomain, and cold transfer the caller there.
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 yourreturnTarget. 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.
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’stransfer 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.