Skip to content
Status

Telnyx IVR integration guide

This guide covers how to integrate Shuttle payments into your Telnyx IVR workflows using the <Pay> TeXML verb for self-service payment collection. Telnyx sends the payment details straight to the Shuttle Pay connector, so you do not need a Twilio account to take payments on Telnyx calls.

The Telnyx <Pay> verb collects payment details during a phone call. Customers enter their card or bank details using their phone keypad in response to voice prompts, without agent involvement. Telnyx passes the details to Shuttle, which charges or tokenises them through your payment gateway. Your application receives the result, never the card details.

Telnyx implements the same pay connector contract as Twilio, so the Shuttle Pay connector reference applies, with two differences:

  • Currency. Telnyx always sends USD to the connector. Pass the real currency as <Parameter name="currency"> on every charge.
  • Results. Telnyx does not pass Shuttle’s response back to your action URL. Read the result from Shuttle with the result lookup.
  • A Telnyx account with a TeXML application handling your calls
  • A Shuttle instance key and secret key
  • A payment gateway connected to your Shuttle instance
  • An HTTPS endpoint you control that can return TeXML
  1. Log into the Telnyx Portal
  2. In the Voice Suite, go to Programmable Voice > Payment connectors
  3. Select Create Connector

Telnyx Payment Connectors

  1. Enter these settings:
Field Value
Connector name shuttle-pay-connector (or similar - note this for later use)
Mode test until you are ready to take real payments
Endpoint URL https://app.shuttleglobal.com/c/api/telnyxpay
Authentication type basic
Username Your Shuttle instance key
Password Your Shuttle secret key

The Endpoint URL is Shuttle, not your application. Telnyx sends the collected details there and expects Shuttle’s reply. If it points at your TeXML endpoint, or the username and password are not your instance key and secret key, every payment fails with payment-connector-error and no PayErrorCode.

When you are ready to take real payments, switch the connector to live from the toggle in the connector list.

Switch to live mode

A live connector cannot be edited, and cannot be switched back to test. To change its endpoint or credentials, delete it and create it again. Test connectors can be edited.

You can also manage connectors through the Telnyx API.

The <Pay> verb is added to your TeXML to collect payment details. See the Telnyx Pay documentation for the full reference.

Telnyx parameters:

Parameter Required Description
paymentConnector Yes Your connector name (e.g., shuttle-pay-connector)
action Yes URL for next TeXML instructions after payment
method No POST or GET for the action request (default: POST)
chargeAmount No Amount to charge, in major units - omit for tokenisation only
transactionType No charge or tokenize (default: inferred from chargeAmount)
paymentMethod No credit-card or ach-debit (default: credit-card)
postalCode No Collect a postal code for AVS (default: true)
timeout No Seconds allowed for each entry (default: 5) - we recommend 30
maxAttempts No Attempts allowed for each entry, 1-3 (default: 1) - we recommend 3
statusCallback No URL for progress updates
description No Transaction description

Set timeout="30" and maxAttempts="3". Telnyx’s defaults give the caller five seconds and one attempt per entry, which is too short to key a card number by hand.

Telnyx’s own currency attribute only accepts USD, so Shuttle ignores it. Use the currency parameter below instead.

Transaction types:

Type chargeAmount Shuttle action Result
Tokenisation Omit - Card saved, no charge
Payment (capture) Set amount PAYMENT Card charged immediately
Payment (auth only) Set amount AUTH Funds held, capture later
Payment + save card Set amount Include save_card=true Card charged and saved

Shuttle parameters are passed as <Parameter> elements within the <Pay> verb. See the Shuttle Pay connector reference for the full list. These are the ones to get right on Telnyx:

Parameter Rule on Telnyx
currency Required on every charge. The ISO currency code, e.g. USD or GBP
bank_account_type Required for ACH: checking, savings or businessChecking
AVSName Required for ACH: the account holder’s name
alt_key Recommended on every <Pay>: your own reference, unique per attempt, used to look up the result

ACH works as on Twilio: always pass bank_account_type and AVSName, because neither carrier collects them. Use parameter names exactly as shown: most are case-sensitive. The only exceptions on Telnyx are AVSName, currency and bank_account_type, which are matched whatever their case.

A charge without currency, or an ACH payment without its account type or holder name, is rejected with INVALID_REQUEST before it reaches your gateway.

Save a card for future use without charging:

<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/next_step"
timeout="30"
maxAttempts="3">
<Parameter name="alt_key" value="SAVE-12345-1"/>
</Pay>
<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/next_step"
chargeAmount="29.99"
postalCode="false"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Parameter name="save_card" value="true"/>
<Parameter name="alt_key" value="INV-12345-1"/>
</Pay>

Hold funds for later capture:

<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/next_step"
chargeAmount="99.99"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Parameter name="action" value="AUTH"/>
<Parameter name="alt_key" value="AUTH-12345-1"/>
</Pay>
<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/next_step"
chargeAmount="49.99"
paymentMethod="ach-debit"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Parameter name="bank_account_type" value="checking"/>
<Parameter name="AVSName" value="John Smith"/>
<Parameter name="alt_key" value="INV-12346-1"/>
</Pay>

See ACH-specific parameters for the other bank details you can pass.

<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/next_step"
chargeAmount="19.99"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Parameter name="frequency" value="MONTHLY"/>
<Parameter name="occurrences" value="12"/>
<Parameter name="start_date" value="2027-01-01T00:00:00"/>
<Parameter name="alt_key" value="SUB-12345-1"/>
</Pay>
<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/payment_complete"
chargeAmount="149.99"
description="Premium Plan - Monthly"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Parameter name="alt_key" value="SUB-2024-001"/>
<Parameter name="account_crm_key" value="cus_123456"/>
<Parameter name="account_first_name" value="Jane"/>
<Parameter name="account_last_name" value="Doe"/>
<Parameter name="account_email" value="jane.doe@example.com"/>
<Parameter name="metadata_plan" value="premium"/>
<Parameter name="metadata_billing_cycle" value="monthly"/>
</Pay>

Pass the cardholder’s billing address with billing_* parameters if your payment gateway performs address verification. The account_* parameters carry customer identity only - they do not include an address. See the Shuttle Pay connector reference for the full field list.

<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/payment_complete"
chargeAmount="49.99"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Parameter name="account_first_name" value="Jane"/>
<Parameter name="account_last_name" value="Doe"/>
<Parameter name="billing_line1" value="123 Main Street"/>
<Parameter name="billing_line2" value="Apt 4B"/>
<Parameter name="billing_line4" value="Springfield"/>
<Parameter name="billing_line5" value="62704"/>
<Parameter name="billing_line6" value="IL"/>
<Parameter name="billing_country" value="US"/>
</Pay>

Customise the messages spoken to callers using the <Prompt> element, with the text in a nested <Say>. The for attribute names the step: payment-card-number, expiration-date, postal-code, security-code, bank-routing-number or bank-account-number. See the Telnyx Pay documentation for prompts that vary by attempt, error or card type.

<Pay
paymentConnector="shuttle-pay-connector"
action="https://yourapp.com/next_step"
chargeAmount="29.99"
timeout="30"
maxAttempts="3">
<Parameter name="currency" value="USD"/>
<Prompt for="payment-card-number">
<Say>Please enter your card number using your phone keypad</Say>
</Prompt>
<Prompt for="expiration-date">
<Say>Now enter the expiration date</Say>
</Prompt>
<Prompt for="security-code">
<Say>Finally, enter the three digit security code</Say>
</Prompt>
</Pay>

Telnyx sends a request to your action URL when <Pay> completes. It reports Telnyx’s own outcome, but it does not pass Shuttle’s response through: there are no PayConnector_ fields, and on a decline Telnyx drops Shuttle’s payment ID and decline message.

Telnyx fields:

Field Description
PayResult success or failed
Result Detailed outcome, e.g. success, payment-connector-error, validation-error, too-many-failed-attempts, cancelled
TransactionId Telnyx’s ID for this payment - use it to look up the result
ChargeId / PaymentConfirmationCode Shuttle payment ID (successful charges only)
TokenId / PaymentToken Shuttle payment method ID (successful tokenisations only)
PayErrorCode Shuttle’s error code, when Shuttle declined or rejected the payment
PaymentError Telnyx’s description of the error - connector_error when Shuttle declined it
PaymentCardNumber Masked card number
PaymentCardType Card brand (visa, mastercard, etc.)

Important: Always look up the result before you tell the caller what happened. success only means Shuttle did not return an error: the payment can still be pending or under review.

What the outcome means:

What you receive Meaning What to do
PayResult=success Shuttle accepted the payment Look up the result and check status
Result=payment-connector-error with a PayErrorCode Shuttle declined or rejected the payment Look up the result for the decline reason
Result=payment-connector-error without a PayErrorCode Shuttle’s answer did not reach Telnyx in time. The payment may have succeeded Look up the result. If it is not found yet, wait a few seconds and try again. Never treat this as a failure without checking
Any other Result The caller did not complete entry, so nothing was sent to Shuttle Offer to try again

Shuttle keeps its answer to every payment request Telnyx sends it, whether the payment succeeded or failed. Read it with the same instance key and secret key you gave the connector:

Method Path Use
GET /c/api/telnyxpay/{TransactionId} When your action URL received TransactionId
GET /c/api/telnyxpay?alt_key={alt_key} By your own alt_key, e.g. when the action request never arrived
Terminal window
curl https://app.shuttleglobal.com/c/api/telnyxpay/{TransactionId} \
-u '{instance_key}:{secret_key}'
curl "https://app.shuttleglobal.com/c/api/telnyxpay?alt_key=INV-12345-1" \
-u '{instance_key}:{secret_key}'

Response fields:

Field Description
transaction_id Telnyx’s transaction ID
alt_key Your alt_key, if you passed one
connector telnyxpay
request_type PAYMENT for a charge, TOKENISE for a tokenisation
updated When Shuttle answered Telnyx
status Primary status - always check this. See below
error { "code", "message" } - the decline or rejection Shuttle returned, including the gateway’s message. null if there was none
payment The payment (charges only)
contract The contract behind the payment (charges only)
payment_method The payment method
charge The first charge (recurring charges only)
transaction The first transaction (recurring charges only)

Card and bank account numbers and security codes are removed.

Status values:

status Meaning
SUCCESS, PENDING, UNRESOLVED, DECLINED, REQAUTH A charge: the payment status, as in Payment status values
ACTIVE A tokenisation: the card or account was saved
INACTIVE A tokenisation: the card or account was not saved - see error
ERROR Shuttle could not create a payment or payment method, e.g. a missing currency parameter or a gateway error - see error

For a recurring payment that starts on a future date, status is the contract’s status until the first charge is taken.

{
"transaction_id": "a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6",
"alt_key": "INV-12345-1",
"connector": "telnyxpay",
"request_type": "PAYMENT",
"updated": "2026-10-12T14:26:53.137Z",
"status": "SUCCESS",
"error": null,
"payment": { "id": "pay_20648_10045", "status": "SUCCESS", "gateway_status": "APPROVED", ... },
"contract": { "id": "co_20648_10045", "status": "COMPLETED", ... },
"payment_method": { "id": "pm_20648_10045", "status": "SINGLEUSE", ... }
}

The payment method is SINGLEUSE because the card was not saved. With save_card=true it is ACTIVE.

{
"transaction_id": "b2c3d4e5-6f7a-8b9c-0d1e-f2a3b4c5d6e7",
"alt_key": "INV-12345-2",
"connector": "telnyxpay",
"request_type": "PAYMENT",
"updated": "2026-10-12T14:31:08.512Z",
"status": "DECLINED",
"error": {
"code": "DECLINED",
"message": "Invalid CVC"
},
"payment": {
"id": "pay_20648_10046",
"status": "DECLINED",
"gateway_status": "DECLINED",
"gateway_message": "Invalid CVC",
...
},
"contract": { "id": "co_20648_10046", ... },
"payment_method": { "id": "pm_20648_10046", ... }
}
{
"transaction_id": "c3d4e5f6-7a8b-9c0d-1e2f-a3b4c5d6e7f8",
"alt_key": "SAVE-12345-1",
"connector": "telnyxpay",
"request_type": "TOKENISE",
"updated": "2026-10-12T14:35:41.008Z",
"status": "ACTIVE",
"error": null,
"payment_method": { "id": "pm_20648_10047", "status": "ACTIVE", ... }
}

Errors:

Status Meaning
404 No result found. Nothing reached Shuttle for that ID, it is more than 24 hours old, or Shuttle is still processing the payment - try again after a few seconds
401 The credentials do not belong to the instance that took the payment
400 Neither a transaction ID nor an alt_key was given

Good to know:

  • Results are kept for 24 hours. After that, retrieve the payment or payment method by ID.
  • Make alt_key unique per attempt, e.g. ORDER-123-1, then ORDER-123-2 if the caller tries again. If you reuse an alt_key, the lookup returns the most recent attempt only. It finds tokenisations as well as charges.

Shuttle webhooks are sent from Shuttle to your backend, separately from Telnyx’s callbacks, so you keep a record of every payment even when a call drops part way through. See the Shuttle Pay connector reference for events and configuration.

After a successful payment, use the Shuttle API for refunds, captures, voids and charging saved cards. See the Shuttle Pay connector reference.

New connectors start in test mode. A test connector still sends payments to Shuttle, but Telnyx only accepts its own test card numbers, such as 4111111111111111 (Visa), 5555555555554444 (Mastercard) and 378282246310005 (American Express) - any other card is rejected as invalid-card-number.

Point a test connector at a Shuttle sandbox instance with a Sandbox Gateway, so no real payment is taken. All three cards above are Sandbox Gateway test cards, approved with any expiry date that hasn’t passed and a 3-digit security code (4 digits for American Express).

Telnyx rejects the Sandbox Gateway’s decline cards, so test declines with the security code instead: on the Visa or Mastercard card, a security code from 901 to 906 returns a decline or an unresolved payment, and 900 a pending one. See CVC triggers. The triggers don’t apply to American Express.

For ACH, Telnyx’s test connector accepts any routing and account number of a valid length, but the Sandbox Gateway only accepts its own test ACH accounts, in USD: use routing number 110000000 with account number 000123456789 for an approval. Any other account is declined.

Before you go live, run a card charge, an ACH charge, a tokenisation and a decline end to end, and check the lookup returns each one. If you record calls, also retrieve the recording of a test payment and confirm the caller’s key presses are not in it.

Shuttle supports the Shuttle Pay connector and the payment - declines, gateway responses, tokenisation, webhooks and the Shuttle API. When raising a payment with us, include the TransactionId or your alt_key. For TeXML, <Pay>, the Telnyx Portal, DTMF and call recording, contact Telnyx support.

Was this page helpful?