Twilio Pay Integration Architecture

This page explains how cardholder data moves between the four parties involved in a Twilio Pay transaction. Understanding the flow helps you reason about PCI scope, what your systems can and cannot see, and how to design around failure.

The Four Parties

PartyRole
Your PlatformInitiates the call flow and orchestrates the payment. Never touches raw card data.
TwilioThe telephony provider. Captures card digits from the caller's keypad inside its PCI-certified voice platform.
ShuttleTwilio's payments partner. Receives card data from Twilio via the Pay Connector and routes it to one of many supported gateways.
Payment GatewayAuthorizes the card and returns an approval or decline.

The relationship to keep in mind: Twilio handles telephony, Shuttle handles payments. Shuttle is the piece that lets a single Twilio connector fan out to whichever gateway your merchant uses.

High-Level Flow

Your platform is the initiator — the call routes to Twilio because your application's voice webhook tells it to, and the session returns to your platform when Twilio finishes.

flowchart LR
  A[Your Platform] -->|Routes call<br/>to Twilio| B[Twilio<br/>captures DTMF]
  B -->|Card data<br/>via connector| C[Shuttle]
  C -->|Authorize| D[Gateway]
  D -->|Gateway token +<br/>reference + status| C
  C -->|Masked card +<br/>Shuttle IDs +<br/>gateway IDs| B
  B -->|Callback| A
  C -.->|Webhook async| A

Raw card data only ever lives inside Twilio → Shuttle → Gateway. Your platform receives the masked PAN, non-sensitive Shuttle and gateway identifiers, and status — never the full PAN or CVV.

What Your Platform Receives

Two independent response paths land on your platform, and they carry different kinds of information.

Twilio callback

Delivered to your action URL (IVR) or StatusCallback URL (Agent Assist) the moment the session completes. This is the detailed payload, including:

  • Masked PAN, card brand, and expiry (for display)
  • Shuttle identifiers — Shuttle payment ID (PaymentConfirmationCode) and Shuttle payment method ID (PayConnector_payment_method). Use these with the Shuttle API for a standardized interface that works identically across every supported gateway
  • Gateway identifiers — gateway transaction reference (PayConnector_gateway_reference) and gateway card token (PayConnector_gateway_token). Use these if you want to interact directly with the underlying gateway (native reconciliation, gateway-specific tooling)
  • Status fields (PayConnector_payment_status, PayConnector_gateway_status)

Neither identifier set is sensitive — they are references, not card data. Most integrations use the Shuttle IDs so they don't need gateway-specific code, and keep the gateway IDs on file for reconciliation.

For the full list of fields, see the Shuttle Pay Connector Reference.

Shuttle webhook

Delivered directly from Shuttle when a payment event occurs (including async ones: pending settlements, held transactions, recurring charges). The webhook is an event notification, not a full transaction record — it carries the event type and references to the affected resources (account, transaction, capture, contract). Use those references to fetch the full details via the Shuttle API when you need them.

For event types and payload shapes, see the webhook events reference.

Which to trust

The Twilio callback is reliable for the session itself — if the caller hangs up mid-flow, Twilio still fires the callback with Result=caller-hung-up rather than dropping it. Use the callback as your primary signal and the callback payload for display and immediate business logic.

Use the Shuttle webhook as the source of truth for anything that resolves after the call ends — pending settlements, held transactions, gateway responses that arrived late, and recurring/scheduled charges. Shuttle retries its webhooks until acknowledged.

PCI Scope

Because DTMF digits are intercepted by Twilio before they reach any of your systems, and because Twilio suppresses the tones so agents on the call cannot hear them, your infrastructure stays outside PCI DSS scope — typically reducing your obligation to an SAQ A self-assessment. Shuttle's instance and secret keys are stored in the Twilio connector configuration, not on your platform, so the card-submission leg never touches your credentials either.

Confirm your specific obligations with your QSA — this is guidance, not legal advice.

IVR vs Agent Assist

Both integrations share the same data flow. They differ in how the session is initiated and controlled.

IVR (<Pay> verb)

Your platform responds to Twilio's voice webhook with TwiML containing a <Pay> verb. The caller interacts only with Twilio.

sequenceDiagram
  participant Caller
  participant Twilio
  participant YourApp as Your Platform
  participant Shuttle
  participant Gateway

  Caller->>Twilio: Calls number
  Twilio->>YourApp: Voice webhook
  YourApp->>Twilio: TwiML with <Pay>
  Twilio->>Caller: Prompts for card
  Caller->>Twilio: DTMF digits
  Twilio->>Shuttle: Card data (connector)
  Shuttle->>Gateway: Authorize
  Gateway->>Shuttle: Approval + token
  Shuttle->>Twilio: Masked card + IDs
  Twilio->>YourApp: POST to action URL
  Shuttle-->>YourApp: Webhook (async)

Agent Assist (Payments Subresource API)

Your backend drives the session programmatically, letting an agent UI trigger each field capture. The agent cannot hear the DTMF tones.

sequenceDiagram
  participant Caller
  participant Twilio
  participant Agent as Agent UI
  participant Backend as Your Backend
  participant Shuttle
  participant Gateway

  Agent->>Backend: Start payment
  Backend->>Twilio: POST /Payments
  loop For each field
    Agent->>Backend: Capture field
    Backend->>Twilio: POST Capture=...
    Twilio->>Caller: Prompts for field
    Caller->>Twilio: DTMF digits
    Twilio->>Backend: StatusCallback
    Backend->>Agent: Push UI update<br/>(WebSocket / poll)
  end
  Agent->>Backend: Complete
  Backend->>Twilio: Status=complete
  Twilio->>Shuttle: Card data (connector)
  Shuttle->>Gateway: Authorize
  Gateway->>Shuttle: Approval + token
  Shuttle->>Twilio: Masked card + IDs
  Twilio->>Backend: Final StatusCallback
  Shuttle-->>Backend: Webhook (async)

Reusing Saved Cards

A card gets saved in two scenarios:

  • Tokenization session — you call <Pay> (or the Payments API) with no chargeAmount. The card is tokenized but not charged.
  • Charge + save — you pass save_card=true alongside a charge.

In both cases, the gateway creates the durable token and Shuttle stores a reference to it against a Shuttle payment method record (pm_...). You get both identifiers back: the Shuttle payment method ID and the gateway token.

Once the card is saved, subsequent charges don't need Twilio — Twilio is only in the path when a human is on the line entering digits. You have two options for how to charge it:

flowchart LR
  A[Later charge] -->|pm_... + amount| B[Shuttle API]
  A -->|gateway_token + amount| D[Gateway directly]
  B -->|Uses stored<br/>gateway_token| D
  D -->|Approval| B
  D -->|Approval| A
  B -->|Payment result| A
  • Via Shuttle — pass the Shuttle pm_... ID to the Shuttle API. Shuttle looks up the gateway token and submits the charge. Your code stays identical across every supported gateway.
  • Via the gateway directly — use the gateway token with your own gateway integration. Useful if you already have gateway-native tooling or want to bypass Shuttle for specific flows.

Most integrations go through Shuttle so they don't need gateway-specific code, but the gateway-direct path stays open.

Connector Timeout and Retry

There are two timeouts stacked on top of each other: Twilio's deadline on Shuttle, and Shuttle's deadline on the gateway.

Twilio → Shuttle (10 seconds)

Twilio enforces a 10-second response deadline on the call it makes to the Shuttle Pay Connector. If Shuttle hasn't responded within that window, Twilio automatically retries the connector call, reusing the same transaction_id as an idempotency key. Retries continue up to 5 times (6 attempts total) before Twilio gives up.

Shuttle's connector uses the transaction_id to dedupe — if the original authorization eventually succeeds while Twilio is retrying, the retry returns the same result rather than creating a duplicate charge.

Shuttle → Gateway (45 seconds)

Shuttle enforces its own 45-second deadline on the underlying gateway. If the gateway hasn't returned a definitive result by then, Shuttle marks the transaction as UNRESOLVED — meaning the outcome cannot be determined from the original request.

For gateways that support it, Shuttle schedules background reconciliation jobs — at +1 minute and +15 minutes — to check the gateway and confirm the outcome. When a job resolves the state, Shuttle:

  • Transitions the transaction to APPROVED or DECLINED
  • Fires the corresponding Shuttle webhook

Reconciliation support varies by gateway. Contact Shuttle support to confirm whether your gateway is covered.

In this edge case, the Twilio callback is not updated — the session already completed from Twilio's perspective, so only the Shuttle webhook will carry the final state. This is unlikely to happen in production other than at scale, but worth designing for: if you see UNRESOLVED, trust the Shuttle webhook to deliver the final outcome rather than treating it as a terminal state.

Failure Modes

The Connector Timeout and Retry section above covers slow-gateway and unresolved scenarios. The table below covers the remaining cases.

Where it failsSymptomWhat to do
Caller hangs up mid-sessionCallback fires with Result=caller-hung-up, no Shuttle dataLikely abandoned; no charge is typically attempted. Reconcile via the Shuttle webhook if a later UNRESOLVED arrives
Gateway declinePayConnector_payment_status = DECLINED, reason in PayConnector_gateway_statusShow a reason, allow retry
Connector credentials wrongTwilio returns Result: success but no PayConnector_* fieldsDetect the missing PayConnector_payment_status and treat as failure

Credentials

CredentialHeld byPurpose
Twilio Account SID / Auth TokenYour backend (Agent Assist only)Authenticate to the Twilio Payments API
Shuttle instance key / secret keyTwilio connector configAuthenticate Twilio → Shuttle during card submission
Shuttle API keyYour backendPost-payment operations (refunds, captures, reuse)

Rotating your Shuttle instance/secret keys requires updating the connector in the Twilio Console — they are not held on your platform during the call.

See Also