# Twilio IVR integration guide

> This guide covers how to integrate Shuttle payments into your Twilio IVR workflows using the <Pay> TwiML verb for self-service payment collection. For agent-ass

This guide covers how to integrate Shuttle payments into your Twilio IVR workflows using the `<Pay>` TwiML verb for self-service payment collection. For agent-assisted payments, see the [Twilio Agent Assist integration guide](/merchants/twilio/agent-assist-guide/).

## Overview

The [Twilio `<Pay>` verb](https://www.twilio.com/docs/voice/twiml/pay) enables automated DTMF payment collection during phone calls. Customers enter their card details using their phone keypad in response to voice prompts, without agent involvement.

## Prerequisites

Complete the setup steps in the [Introduction](/merchants/twilio/intro/#getting-started):
- Enable PCI Mode on your Twilio account
- Install the Shuttle Pay connector

## Twilio `<Pay>` verb

The `<Pay>` verb is added to your TwiML to collect payment details. See the [Twilio Pay documentation](https://www.twilio.com/docs/voice/twiml/pay) for the full reference.

**Twilio parameters:**

| Parameter | Required | Description |
|-----------|----------|-------------|
| `paymentConnector` | Yes | Your connector name (e.g., `shuttle-pay-connector`) |
| `action` | Yes | URL for next TwiML instructions after payment |
| `chargeAmount` | No | Amount to charge - omit for tokenisation only |
| `currency` | No | ISO currency code, lowercase (default: `usd`) |
| `paymentMethod` | No | `credit-card` or `ach-debit` (default: `credit-card`) |
| `postalCode` | No | AVS postal code collection (default: `true` for US/CA) |
| `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"`.** Twilio's defaults give the caller five seconds and one attempt per entry, which is too short to key a card number by hand.

**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](/merchants/twilio/shuttle-connector-reference/#request-parameters) for the full list.

## Examples

### Card tokenisation

Save a card for future use without charging:

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/next_step"
  timeout="30"
  maxAttempts="3">
</Pay>
```

### Standard card payment

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/next_step"
  chargeAmount="29.99"
  currency="usd"
  postalCode="false"
  timeout="30"
  maxAttempts="3">
  <Parameter name="save_card" value="true"/>
  <Parameter name="alt_key" value="INV-12345"/>
  <Prompt for="payment-processing">
    <Say>Please wait while we process your payment</Say>
  </Prompt>
</Pay>
```

### Pre-authorisation

Hold funds for later capture:

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/next_step"
  chargeAmount="99.99"
  timeout="30"
  maxAttempts="3">
  <Parameter name="action" value="AUTH"/>
</Pay>
```

### ACH payment

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/next_step"
  chargeAmount="49.99"
  paymentMethod="ach-debit"
  timeout="30"
  maxAttempts="3">
  <Parameter name="bank_account_type" value="checking"/>
  <Parameter name="AVSName" value="John Smith"/>
  <Prompt for="payment-processing">
    <Say>Processing your bank transfer</Say>
  </Prompt>
</Pay>
```

ACH payments need the `bank_account_type` parameter, set to `checking`, `savings` or `businessChecking`, and the `AVSName` parameter. See [ACH-specific parameters](/merchants/twilio/shuttle-connector-reference/#ach-specific).

### Recurring payment

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/next_step"
  chargeAmount="19.99"
  timeout="30"
  maxAttempts="3">
  <Parameter name="frequency" value="MONTHLY"/>
  <Parameter name="occurrences" value="12"/>
  <Parameter name="start_date" value="2027-01-01T00:00:00"/>
</Pay>
```

### With full traceability

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/payment_complete"
  chargeAmount="149.99"
  description="Premium Plan - Monthly"
  timeout="30"
  maxAttempts="3">
  <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>
```

### With billing address (AVS)

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](/merchants/twilio/shuttle-connector-reference/) for the full field list.

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/payment_complete"
  chargeAmount="49.99"
  timeout="30"
  maxAttempts="3">
  <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>
```

### Customising voice prompts

Customise the messages spoken to callers using the `<Prompt>` element. See [Twilio's Prompt documentation](https://www.twilio.com/docs/voice/twiml/pay/prompt) for all prompt types.

```xml
<Pay
  paymentConnector="shuttle-pay-connector"
  action="https://yourapp.com/next_step"
  chargeAmount="29.99"
  timeout="30"
  maxAttempts="3">
  <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>
  <Prompt for="payment-processing">
    <Say>One moment while we securely process your payment</Say>
  </Prompt>
</Pay>
```

:::tip
Use pre-recorded audio with `<Play>` instead of `<Say>` for a more polished experience.
:::

## Handling responses

Twilio sends a POST request to your `action` URL with the payment results.

> **Important:** Always check `PayConnector_payment_status` - Twilio may return `Result: "success"` even when the payment failed.

**Twilio fields:**

| Field | Description |
|-------|-------------|
| `Result` | Twilio status code |
| `PaymentCardNumber` | Masked card number |
| `PaymentCardType` | Card brand (visa, mastercard, etc.) |

**Shuttle fields** (prefixed with `PayConnector_`):

| Field | Description |
|-------|-------------|
| `PayConnector_payment_status` | Primary status - always check this |
| `PayConnector_gateway_reference` | Gateway transaction ID |
| `PayConnector_gateway_token` | Tokenised card (when `save_card=true`) |
| `PaymentConfirmationCode` | Shuttle payment ID |

For the complete list of response fields, status values and example responses, see the [Shuttle Pay connector reference](/merchants/twilio/shuttle-connector-reference/#response-fields).

## Shuttle webhooks

Shuttle webhooks are sent from Shuttle to your backend, separately from Twilio's callbacks, so you keep a record of every payment - IVR or Agent Assist - even when a call drops part way through. See the [Shuttle Pay connector reference](/merchants/twilio/shuttle-connector-reference/#webhooks) for events and configuration.

## Post-payment operations

After a successful payment, use the Shuttle API for refunds, captures, voids and charging saved cards. See the [Shuttle Pay connector reference](/merchants/twilio/shuttle-connector-reference/#shuttle-api).

## References

- [Twilio Pay documentation](https://www.twilio.com/docs/voice/twiml/pay) - Full `<Pay>` verb reference
- [Twilio Prompt documentation](https://www.twilio.com/docs/voice/twiml/pay/prompt) - Voice prompt customisation
- [Shuttle Pay connector reference](/merchants/twilio/shuttle-connector-reference/) - Parameters, responses, webhooks
- [Demo application source](https://github.com/shuttle-global/twilio-demo-app)