Telnyx
Take PCI-compliant payments on Telnyx voice calls, without moving your telephony to another provider. This guide shows how to route only the payment segment of a Telnyx call through Twilio <Pay> and Shuttle, capture the payment details by DTMF, and return the caller to your own Telnyx flow. Cards and ACH bank debit are both supported.
About Telnyx
Telnyx is a communications platform and carrier that provides programmable voice, SIP trunking and phone numbers. Its Call Control API and TeXML let you control calls in real time — answering, bridging, transferring and dialling out — and its Elastic SIP Trunking connects your own PBX or contact centre platform to the PSTN.
If you take payments over the phone, you need a way to capture the caller's card or bank account number as DTMF keypad tones without those tones reaching your agents, your call recordings or your own servers. That is what keeps a contact centre out of PCI DSS scope, and it needs a payment-aware capture layer in the voice path.
Shuttle provides that layer. You keep your numbers, routing and call logic on Telnyx, and hand the caller over for the payment segment only. Card data is captured inside a PCI-compliant environment and passed to Shuttle, which charges it through your existing payment gateway. Your application receives the result — never the card details.
Use this guide if you want to:
- Take card or ACH payments on inbound or outbound Telnyx calls
- Capture card and bank account numbers by DTMF without the digits reaching your agents or recordings
- Add payments to a Telnyx IVR or Call Control application
- Keep your existing carrier, numbers and call routing on Telnyx
- Charge through the payment gateway you already use, via Shuttle
The same approach works for any carrier or platform that can transfer a call to an external SIP address — the Telnyx API calls below are the only Telnyx-specific part. If you are on a different platform, see Bring Your Own Carrier.
This guide is a pointer, not a specification. It describes one approach that works — there are many ways to build this, and yours may differ depending on your carrier, PBX or contact centre platform. Telnyx and Twilio are independent vendors and change their products, APIs and consoles independently of this guide.
Shuttle does not provide technical support for Telnyx or Twilio. For anything on either platform — transfers, SIP connections, credentials, codecs, DTMF behaviour, PCI Mode, billing — obtain official technical support from the vendor concerned. Verify every step below against current Telnyx and Twilio documentation, and test end to end before going live. Shuttle supports the Shuttle Pay Connector and the payment itself.
How it works
Your call stays on Telnyx. When it is time to take payment, Telnyx sends the caller to a SIP address on your Twilio account. Twilio asks your application what to do, you return a <Pay> verb, and Twilio captures the card and passes it to Shuttle.
Caller
|
| PSTN
v
Telnyx ------- SIP INVITE (+ custom headers) -------> Twilio SIP Domain
^ |
| | webhook
| v
| Your TwiML endpoint
| |
| returns <Pay>
| |
| v
| DTMF capture
| |
| v
| Shuttle Pay Connector
| |
| v
| Shuttle -> Gateway
| |
+---------------- caller returns to your flow -------------+
Cardholder data is captured inside Twilio's PCI environment and passed to Shuttle by the Pay Connector. Your application never receives card details.
Choose your call flow
There are two ways to send the caller to Twilio. Which one is right for you is a compliance question rather than a technical preference, so work out the answer before you read the options.
Why there is a choice at all
PCI DSS scopes any system that stores, processes or transmits cardholder data. A card number keyed on a phone keypad is cardholder data, so anything it passes through — or is recorded into — falls in scope. There is no exemption for equipment that merely passes it along.
Telnyx, Twilio and Shuttle each hold their own PCI DSS compliance. That covers our platforms; it does not transfer to yours. Three separate things can pull your own environment into scope, and they are independent of each other:
- Media path. DTMF travels in the RTP stream, either as inband audio tones or as RFC 2833 / 4733 telephone-event packets. Any SBC, PBX or media server the RTP crosses is transmitting cardholder data.
- Signalling path. DTMF can instead be carried out of band as SIP INFO messages. Where that is what gets negotiated, sitting in the signalling path is enough on its own — media bypass does not save you.
- Call recording. A recording made while the caller keys their card stores the card number. If they key a CVV, it stores sensitive authentication data, which PCI DSS prohibits retaining after authorisation under any circumstances, encrypted or not. This is the one that catches people out, because it applies even when you have successfully kept your equipment out of both paths — the recording is yours wherever it lives.
The two options below differ in whether the media and signalling cross your own equipment, and that also decides what happens to your recording:
- Bridge keeps the Telnyx leg alive throughout, so a running Telnyx recording captures the payment. You have to stop it yourself.
- Handoff ends the Telnyx leg when the call moves, so the recording ends with it.
Two cases where handoff does not save you: if the REFER fails and your code falls back to bridging, the fallback path still needs recording stopped; and if recording happens upstream of the divert point — on your carrier's trunk or a compliance recorder — the call still passes through it. Twilio's PCI Mode protects recordings and logs on the Twilio side only.
Which one applies to you
Option A (Bridge) if both of these are true:
- Either your calls run entirely on Telnyx Call Control with no SBC or PBX of your own in the media path, or you already maintain a cardholder data environment and are not adopting this integration in order to reduce your PCI scope, and
- You can stop call recording for the payment segment and restart it afterwards, reliably, on every call
Option B (Handoff) if any of these is true:
- You operate your own SBC, PBX or contact centre platform that the call audio flows through, and you are adopting DTMF capture to keep that equipment out of PCI scope
- You record calls on Telnyx and would rather the payment segment sit structurally outside the recording than depend on stopping and restarting it correctly every time
- Your recording obligations do not permit a gap mid-call, so stopping the recording is not available to you
Recording deserves its own line here because stopping it is a procedural control. If it fails once — a missed API call, an error swallowed, a code path nobody tested — a card number is in your archive permanently, and if the caller keyed a CVV you are holding data PCI DSS does not allow you to retain at all. Handoff makes it structural: there is no leg left to record.
Option B only works if your upstream carrier honours SIP REFER, and many do not. Confirm that with your carrier before you design around it — if they do not, Option A is your only route and you will need to account for your equipment in your scope assessment.
Your QSA determines your scope, not this guide. Twilio's and Shuttle's PCI compliance covers our platforms, not yours.
At a glance
| Option A: Bridge | Option B: Handoff | |
|---|---|---|
| Telnyx command | transfer | refer |
| Media path during payment | Through Telnyx | Carrier direct to Twilio |
| Your own equipment in the card data path | Yes, if you operate an SBC or PBX | No |
| Telnyx call recording | You must stop it before transferring | Ends with the leg, but cover your fallback |
| Caller returns to your flow | Automatically | Twilio must dial back |
| Carrier support needed | None | Upstream carrier must honour SIP REFER |
Prerequisites
- A Telnyx account with a Call Control or TeXML application handling your inbound calls
- A Twilio account, upgraded (not trial)
- A Shuttle instance key and secret key
- An HTTPS endpoint you control that can return TwiML
Step 1: Twilio setup
Enable PCI Mode and install the Pay Connector
Follow Step 1 of the Introduction to enable PCI Mode and install the Shuttle Pay Connector.
Important: Enabling PCI Mode is irreversible and redacts sensitive data from every log in that Twilio project. Use a dedicated Twilio subaccount for payments so the change does not affect logging on your other voice traffic.
Note the connector's Unique Name — you will reference it in the <Pay> verb.
Create a SIP Domain
You do not need a Twilio phone number. A SIP Domain gives you a SIP address that Telnyx can dial, and it points at a webhook exactly as a phone number does.
- In Twilio Console, go to Voice > Manage > SIP Domains and click Create new SIP Domain
- Set a SIP URI — for example
acme-payments.sip.twilio.com - Under Voice Configuration, set A CALL COMES IN to Webhook, enter your TwiML endpoint URL, and set the method to HTTP POST
- Set the Primary Handler Fails fallback URL to the same endpoint or a static failure handler
- Set the SIP Region closest to your callers — use Ireland (ie1) for UK and European traffic
Region matters:
<Pay>is available in the US, Ireland and Australia only. Routing UK or EU calls through a US region adds latency that degrades DTMF capture reliability.
Add voice authentication
Twilio will not accept SIP calls to a domain with no authentication configured. Choose one:
Credential List (recommended for Telnyx). Twilio challenges the INVITE and Telnyx responds with a username and password.
- Go to Voice > Manage > Credential Lists and create a list with one credential
- Return to your SIP Domain, and under Voice Authentication attach the credential list
IP Access Control List. Only practical if calls originate from static IPs you control. Calls placed by Telnyx Call Control originate from Telnyx's egress ranges, which are numerous and subject to change, so a credential list is the more robust choice.
Step 2: Telnyx setup
Your calls need to be under the control of a Telnyx Call Control or TeXML application so you can issue a transfer when payment is due. No additional Telnyx configuration is required to dial an external SIP URI — the credentials for Twilio are supplied on the transfer command itself.
If you are using Option B (Handoff) and Twilio needs to dial the caller back into Telnyx, enable inbound SIP URI calling on the Telnyx connection that will receive the return call, and set its access control to accept the call. See Telnyx's SIP URI calling documentation for the current options.
Step 3: Send the call to Twilio
Pass the payment context as custom SIP headers on the INVITE. Twilio makes any header prefixed X- available to your webhook, so your TwiML endpoint can read the amount and reference for this specific call without a database lookup.
Prefix your headers X- — Twilio ignores headers without it.
Option A: Bridge
curl -X POST https://api.telnyx.com/v2/calls/{call_control_id}/actions/transfer \
-H "Authorization: Bearer $TELNYX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "sip:[email protected]",
"sip_auth_username": "twilio_credential_username",
"sip_auth_password": "twilio_credential_password",
"custom_headers": [
{ "name": "X-Amount", "value": "4250" },
{ "name": "X-Currency", "value": "gbp" },
{ "name": "X-Ref", "value": "ORD-88231" },
{ "name": "X-Account", "value": "C-991" }
]
}'Telnyx keeps the originating leg. If the transfer fails, you receive a call.hangup webhook for the Twilio leg and the original call stays active, so you can retry or fall back.
Stop recording before you transfer. Because Telnyx holds the originating leg throughout, any Telnyx call recording that is running will capture the DTMF tones the caller keys into Twilio — storing their card number, and their CVV if you collect one. Stop or pause recording using Telnyx's recording controls before issuing the transfer, and resume it after the caller returns. Twilio's PCI Mode protects recordings and logs on the Twilio side; it has no effect on a recording Telnyx is making.
Option B: Handoff
curl -X POST https://api.telnyx.com/v2/calls/{call_control_id}/actions/refer \
-H "Authorization: Bearer $TELNYX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sip_address": "sip:[email protected]",
"sip_auth_username": "twilio_credential_username",
"sip_auth_password": "twilio_credential_password",
"custom_headers": [
{ "name": "X-Amount", "value": "4250" },
{ "name": "X-Currency", "value": "gbp" },
{ "name": "X-Ref", "value": "ORD-88231" }
]
}'You will receive call.refer.started, then either call.refer.completed or call.refer.failed. A failure usually means your upstream carrier does not honour REFER — fall back to Option A.
A successful REFER ends the Telnyx leg, so any Telnyx recording stops with it and you do not need to manage it. Your fallback path does. If call.refer.failed sends you to a bridge transfer, stop recording first, as in Option A above.
Using TeXML instead of Call Control
If your calls are driven by TeXML rather than the Call Control API, <Dial> with a <Sip> noun does the equivalent of Option A. The <Sip> noun accepts username and password attributes for the Twilio SIP authentication challenge:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial answerOnBridge="true">
<Sip username="twilio_credential_username" password="twilio_credential_password">
sip:[email protected]
</Sip>
</Dial>
</Response>Telnyx does not document custom SIP headers on the TeXML <Sip> noun, so pass your reference in the user part of the SIP URI instead — sip:ORD-88231@... above. It arrives at your TwiML endpoint in the To parameter, and you look the payment details up from your own records.
Choosing between them: use Call Control if you want to pass the amount and reference as custom headers and avoid a lookup. Use TeXML with a reference in the SIP URI if your call flow is already TeXML-driven. Both are fine — the URI approach simply moves the context from the INVITE into your own database.
Step 4: Serve the Pay verb
Twilio POSTs to the webhook on your SIP Domain. Your custom headers arrive as request parameters prefixed SipHeader_, and the dialled SIP URI arrives in To.
Verify parameter names first: Before writing your parser, log the full request body from one test call and confirm exactly how Twilio names your headers. Expect
X-Amountto arrive asSipHeader_X_Amount, but confirm rather than assume.
Return a <Pay> verb built from those values:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Pay
paymentConnector="shuttle-pay-connector"
chargeAmount="42.50"
currency="gbp"
description="Order ORD-88231"
action="https://yourapp.com/twilio/payment-result">
<Parameter name="account_crm_key" value="C-991"/>
<Parameter name="alt_key" value="ORD-88231"/>
</Pay>
</Response>Two things to get right:
chargeAmountis a decimal in major units. If you pass amounts in minor units, convert — and handle zero-decimal currencies such as JPY and three-decimal currencies such as KWD.- Escape your XML. An ampersand or angle bracket in a description will produce malformed TwiML and the call will fail.
To capture ACH bank details instead of a card, set paymentMethod="ach-debit" on the <Pay> verb. To tokenise without charging, omit chargeAmount.
For the full list of Shuttle <Parameter> values, see the Shuttle Pay Connector Reference. For <Pay> attributes and transaction types, see the IVR Integration Guide.
<Pay>is not your only option. Once the call is in Twilio, an agent can drive the capture through the Payments Subresource API instead, with the digits still never reaching them — see the Agent Assist Integration Guide. Everything up to and including the transfer is identical either way; only what you do once the call arrives changes.
If the request is missing the headers you expect, return TwiML with a <Say> and <Hangup> and a 200 status. Returning an error status causes Twilio to play its own generic failure message to your caller.
Step 5: Return the call
Option A (Bridge). Nothing to configure. End your TwiML with <Hangup> and the caller is back on the original Telnyx leg.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Hangup/>
</Response>Option B (Handoff). Dial the caller back into Telnyx from your result TwiML:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip>sip:[email protected]</Sip>
</Dial>
</Response>If that Telnyx connection requires authentication, <Sip> accepts username and password attributes. Prefer an unauthenticated or IP-restricted return target where your security policy allows it — credentials placed in TwiML are visible in your Twilio request inspector logs, and PCI Mode redaction does not cover SIP credentials.
Step 6: Receive the result
Twilio POSTs the outcome to the action URL you set on the <Pay> verb, in the call context, before you return your closing TwiML. Shuttle's response fields arrive prefixed PayConnector_:
| Parameter | Description |
|---|---|
Result | Twilio's capture outcome |
PayConnector_payment_status | Shuttle payment status |
PayConnector_gateway_reference | Gateway transaction ID |
PayConnector_gateway_status | Gateway response status |
See the Shuttle Pay Connector Reference for the complete list and for decline types.
Shuttle also emits webhooks for the resulting payment. Use these if you need a durable record independent of the call — the action callback tells you the outcome inside the call so you can play a success or failure message, while webhooks are the reliable audit trail. See the Connector Reference for events and configuration.
Before you go live
Run one real call end to end against a Shuttle sandbox instance and check each of these. The first three are the failures that show up in production rather than in testing.
Use a sandbox gateway and test card numbers rather than a live card — see Testing with Processors and Sandbox Gateway.
- DTMF survives as RFC 2833 telephone-event across every leg. If any hop converts to inband audio, digits are misread and you will capture wrong card numbers intermittently. Test with a full 16-digit test PAN plus expiry and CVV, not a few keypresses.
- Codecs are pinned to G.711 (PCMU or PCMA) on both sides. Twilio SIP accepts G.711 and Opus; anything else means transcoding or no audio.
- Custom headers arrive intact. Confirm the exact
SipHeader_parameter names from a logged request. - Call recording does not capture the payment segment. Make a test payment with recording enabled on your normal flow, then retrieve the recording and confirm the DTMF tones are absent. This is the check most often skipped and the one with the largest consequence.
- SIP authentication succeeds — check the Twilio SIP Domain logs for
401or407failures. - Your TwiML endpoint returns
200with valid XML for malformed input, not a500. - The caller returns to your flow correctly after both a successful and a declined payment.
- Amounts are correct for your currencies, including any zero- or three-decimal currencies you handle.
Troubleshooting
| Symptom | Likely cause |
|---|---|
Call to the SIP domain rejected with 403 | No voice authentication configured, or credentials do not match the attached credential list |
Twilio challenges with 407 and the call fails | sip_auth_username / sip_auth_password missing from the Telnyx command |
| Webhook fires but your headers are absent | Headers not prefixed X-, or stripped in transit — check the INVITE Telnyx actually sent |
| Caller hears Twilio's generic error message | Your TwiML endpoint returned a non-200 status or invalid XML |
| Card digits captured incorrectly or capture times out | DTMF converted to inband audio on one of the legs |
<Pay> fails immediately with a connector error | Connector paymentConnector name does not match the Unique Name in your Twilio console |
call.refer.failed from Telnyx | Upstream carrier does not honour SIP REFER — use Option A |
| Payment succeeds but caller is dropped | Missing or invalid TwiML returned from the action URL |
Where to get help. Shuttle supports the Pay Connector and the payment — declines, gateway responses, tokenisation, webhooks and the Shuttle API. If a payment fails and you have the PayConnector_gateway_reference, raise it with us.
Everything else belongs to the vendor that owns it. For call routing, transfers, SIP connections, codecs, DTMF and recording, contact Telnyx support. For SIP Domains, <Pay>, PCI Mode and connector installation, contact Twilio support. Shuttle cannot raise or escalate tickets on your behalf with either.
References
- Twilio Introduction - PCI Mode and Pay Connector setup
- IVR Integration Guide - Full
<Pay>verb reference - Shuttle Pay Connector Reference - Parameters, responses, webhooks, decline types
- Twilio: Sending SIP to Twilio - SIP Domains, authentication, custom headers
- Testing with Processors - Test card numbers
- Sandbox Gateway - Sandbox setup for end-to-end testing
- Telnyx: Transfer a call
- Telnyx: SIP Refer a call
- Telnyx: TeXML Dial verb
Updated about 1 hour ago