Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

How to capture your first payment using <Pay>

In this tutorial, you will create an interactive voice response (IVR) that collects payment details from a customer and passes the information in a PCI-compliant manner to your payment processor of choice. This tutorial uses a TwiML Bin with the <Pay> verb and the Stripe(link takes you to an external page) Pay Connector to charge a credit card.


In this tutorial you will learn how to:

  1. Enable PCI Mode on your account
  2. Create a Stripe account
  3. Configure a Stripe Pay Connector
  4. Create a TwiML Bin with <Pay>
  5. Create a Twilio Function that handles the payment result and provides new TwiML instructions
  6. Buy a Twilio phone number
  7. Configure the Twilio phone number to use the TwiML Bin for incoming calls
  8. Test capturing credit card details and see the resulting charge on your Stripe account

1. Enable PCI Mode

1-enable-pci-mode page anchor

In order to use any of Twilio's Pay Connectors, you must enable PCI mode on your Twilio account. This ensures that Twilio will capture the payment details from your customers in a PCI-compliant manner and redact any sensitive PCI information from any call logs.



PCI Mode will redact sensitive information from ALL of your account's logs. Turning on PCI Mode cannot be undone.

If you want to avoid redacting information from all logs on an account, consider creating another Twilio account, enable PCI Mode on that account, and use that account when collecting payments with <Pay> or Agent Assist/Payment API.

To enable PCI Mode, complete the following steps:

  1. Navigate to the Twilio Voice Settings(link takes you to an external page) in the Twilio Console. (In the left navigation pane, click on Voice > Settings > General .)
  2. Click on the Enable PCI Mode button.

    Enable PCI Mode.
  3. Click on I Agree on the pop up to accept Twilio's Terms of Service.
  4. Click on the Save button.

2. Create a Stripe Account

2-create-a-stripe-account page anchor

<Pay> allows you to use a variety of payment providers; we will use Stripe for this tutorial.

To get started, head over to Stripe to create your account(link takes you to an external page).

3. Configure Stripe Pay Connector

3-configure-stripe-pay-connector page anchor

In order to authorize Twilio to create charges and create tokens on your behalf, you must connect your Stripe account to Twilio's Stripe Connect platform. Complete the following steps:

  1. In your Twilio Console(link takes you to an external page) , navigate to Pay Connectors(link takes you to an external page) under Voice > Manage > Pay Connectors in the left navigation pane and click on the Stripe Connector tile.
  2. Click on Install .
  3. On the pop-up, read the Terms of Service. Click the checkbox next to I agree to Twilio Inc's Terms of Service and click Agree & Install .
  4. Enter Default for the UNIQUE NAME.

    Use 'Default' as the Unique Name for the Stripe Connector.

    You can create one Pay Connector per Twilio account with the name Default. When <Pay> is invoked, if the paymentConnector attribute is not specified then the Default Pay Connector is used.

  5. Click on Connect with Stripe, which redirects you to Stripe. Enter your Stripe credentials and answer the prompts with with your business details. If your Stripe account has not been activated to allow you to accept payments in live mode, then you can bypass entering your business details at this point and click the link at the top Skip this account form. You are then redirected back to Twilio.

    Click on Connect with Stripe.
  6. You are directed back to the Stripe Connector page in the Twilio Console. Notice that the STRIPE ACCOUNT ID ( acct_XXXXXXXXXXXXXXX ) is now shown on the page. If you have multiple Stripe accounts for Dev/Stage/Prod, the Account ID helps you differentiate these accounts for each Stripe Connector Instance

4. Create a TwiML Bin with <Pay>

4-create-a-twiml-bin-with-pay page anchor

Next, we'll use a TwiML Bin to provide Twilio with the <Pay> TwiML instruction. When Twilio executes the <Pay> verb, a customer will hear prompts to enter their payment information.

  1. Open a new browser tab and navigate to the TwiML Bins page in your Twilio Console(link takes you to an external page) .
  2. Click on the blue + button to create a new TwiML Bin
  3. Give the TwiML Bin a FRIENDLY NAME of " <Pay> with Stripe "
  4. Copy and paste the following TwiML into the TWIML input box:

    <?xml version="1.0" encoding="UTF-8"?>
    <Say>Calling Twilio Pay</Say>
    <Pay paymentConnector="Default" action="" chargeAmount="20.45"/>

    Notice how the <Pay> verb has three attributes: paymentConnector, action, and chargeAmount.
    The paymentConnector attribute's value is the Pay Connector you want to use with this <Pay> verb. In this case, it's the Generic Pay Connector you just created called "Default".
    The action attribute is left blank for now. This attribute will be a URL. Upon the completion of a <Pay> transaction, Twilio will send a webhook to your action URL to get a new set of TwiML instructions. We'll create an endpoint in the next step that handles the request to this this action attribute.
    The chargeAmount attribute is set to 20.45, representing a charge of $20.45. (If you wanted to create a tokenize transaction, you would set this attribute value to 0 or omit the attribute altogether.)

  5. Click the Save button at the bottom of the page.

5. Create a Twilio Function to handle the payment result

5-create-a-twilio-function-to-handle-the-payment-result page anchor

When <Pay> completes capturing the consumers' credit card the Pay Connector initiates a transaction with the Payment Provider. Next, the Twilio sends an HTTP request to <Pay>'s action URL with a status returned.

You will use Twilio's Serverless Functionsto write and host the endpoint for our action URL. Twilio Functions allow you deploy Node.js-based applications without needing to install anything locally on your own machine.

  1. Navigate to the Functions > Services page(link takes you to an external page) in your Twilio Console.
  2. Click on the Create Service button to create a new Functions service.
  3. In the Name your Service pop up, give your service the name pay-with-stripe-action-url
  4. Click Next on the Name your Service pop up.
  5. In the Functions pane on the top left, rename the /path_1 Function to /pay and hit Enter.

    Rename the function to '/pay'.
  6. Next to the /pay path name, you should see a lock icon (When you hover over it, a "Protected" tooltip shows.). Click on the lock icon and click on Public.

    Select Public in the Lock Icon dropdown.
  7. Select all of the provided sample code in the code editor pane and delete it .
  8. Copy and paste the following code into the code editor of your /pay function:

    exports.handler = function(context, event, callback) {
    console.log("in Pay");
    let twiml = new Twilio.twiml.VoiceResponse();
    switch (event.Result) {
    case "success":
    text = "Thank you for your payment";
    case "payment-connector-error":
    text = "The Payment Gateway is reporting an error";
    text = "The payment was not completed successfully";
    callback(null, twiml);

    Your Functions editor should now look like this: \

    Functions editor pane after pasting in correct code.

    This Function checks the Result property in the request from Twilio. If the Result is "success", the Function returns the following TwiML:

    <?xml version="1.0" encoding="UTF-8"?>
    <Say>Thank you for your payment</Say>

    If the Result is "payment-connector-error", the function returns the following TwiML:

    <?xml version="1.0" encoding="UTF-8"?>
    <Say>The payment was not completed successfully</Say>

  9. Click on the blue Save button at the bottom of the code editor pane.
  10. Click the Deploy All button at the bottom of the page. This deploys your Twilio Function to the internet.

    Deploy All Functions Button.
  11. Click on the Enable live logs switch so that you'll see live logs when your /pay endpoint receives a request from Twilio.

    Enable live logs.
  12. Now, copy the URL for your new endpoint by clicking on Copy URL (above the Live logs on toggle).
  13. In a new browser tab, navigate to the <Pay> with Stripe TwiML Bin(link takes you to an external page) you created earlier.
  14. Paste the Function URL from step 12 between the double quotation marks after action= (i.e. in the place of below).

    <?xml version="1.0" encoding="UTF-8"?>
    <Say>Calling Twilio Pay</Say>
    <Pay paymentConnector="Default" chargeAmount="20.45"

  15. Click Save on the TwiML Bin page.

Now it's time to purchase Twilio phone number and configure it to use the <Pay> instructions in the TwiML Bin.

6. Purchase a Twilio phone number

6-purchase-a-twilio-phone-number page anchor

If you don't already own a Twilio Voice-enabled phone number, complete the following steps:

  1. In the Twilio Console, navigate to the Buy a Number(link takes you to an external page) page.
  2. Make sure the "Voice" checkbox is checked and click the Search button.

    Search for a Number - Click on the 'Search' button.
  3. You'll see a list of available phone numbers and their capabilities. Find a number that you like and click the Buy button.

    Buy a phone number - click on the 'Buy' button on the right side of the screen.
  4. In the"Review Phone Number" pop-up, review the information and click on Buy (xxx) xxx-xxxx to confirm your purchase.

7. Configure a Twilio number to use your <Pay> TwiML Bin for incoming calls

7-configure-a-twilio-number-to-use-your-pay-twiml-bin-for-incoming-calls page anchor

Now you'll navigate to the configuration page for the phone number and configure it to use your <Pay> with Stripe TwiML Bin when someone calls the number.

  1. If you see the Number Purchased modal from the last step, click on Configure (xxx) xxx-xxxx . (If you navigated away from the previous step, navigate to Phone Numbers > Active numbers in the left navigation pane and select the phone number you just bought.)
  2. Give the phone number a FRIENDLY NAME of " <Pay> Tutorial ".
  3. Scroll down to the Voice & Fax section.
  4. Find the A CALL COMES IN label.
  5. Click on the dropdown (it currently says "Webhook") and select TwiML Bin .
  6. In the dropdown that says Select a TwiML Bin (directly under the dropdown from the previous step), select <Pay> with Stripe .
  7. Click the blue Save button at the bottom of the page.

8. Test your application

8-test-your-application page anchor

Before you call your Twilio phone number, review what should happen:

  • You dial your Twilio phone number
  • The phone number's configuration points to the <Pay> with Stripe TwiML Bin.
  • Twilio executes the <Pay> verb, so you hear prompts to enter your payment details.
  • You enter your payment details.
  • Twilio sends a request to Stripe via your Default Stripe Pay Connector.
  • Stripe returns a response to Twilio.
  • Twilio sends a request with the result of the payment to your Twilio Function (the URL of <Pay> 's action attribute).
  • The payment is successful, so your Twilio Function sends <Say>Thank you for your payment.</Say> TwiML back to Twilio.
  • You hear "Thank you for your payment" and the call ends.

Test it out

test-it-out page anchor
  1. Call your Twilio number.
  2. Enter your test payment information:

    • Credit card number: 4242 4242 4242 4242
    • Expiry date (MM/YY): 12 25 (pick a date in the future)
    • Zip code: 94105
    • CVC security code: 333
  3. To verify that your application correctly captured this data, navigate to your Call Logs(link takes you to an external page) and click on your most recent call.
    Scroll down to see the Request Inspector. Expand the parameters on the second POST for your call.

    Find Pay status in call logs.
  4. You can navigate over to your Stripe Dashboard(link takes you to an external page), copy the "PaymentConfirmationCode" "ch_xxxxx," and paste into the Stripe search. You should see the following:

    Verify the payment via Stripe.

You can add the line console.log(event); in your Twilio Function's code. (Don't forget to save and deploy the changes.) This prints out the request parameters in the Log to let you inspect the contents.

You can also navigate to your Call Logs in the Console and view the call in more detail.

You will notice a POST request to <Pay>'s action URL for each stage of the call, first ringing state, and then in-progress.

If you expand the second POST request parameters you will see the call status in-progress. The Result field shows information on error causes. Read the <Pay> documentation for more information.

When Stripe rejects a transaction the result is payment-connector-error and you can get further insight by inspecting the PaymentError field.

For instance, if instead of entering 4242 4242 4242 4242 you enter another card then you will see the following:

Stripe payment error example.

Stripe offers a list of test card numbers to help with error handling:

  • 4100 0000 0000 0019 - Card declined
  • 4000 0000 0000 9995 - Card has insufficient funds
  • 4000 0000 0000 0069 - Card expired

See Stripe's full list(link takes you to an external page) of test cards.

If you want a POST request after each payment detail is collected, you can use <Pay>'s statusCallback attribute.

Great work! In a few lines of code, you've captured payment details and charged your customer in test mode.

For more information on <Pay>, including unique attributes you can use to modify your payments, check out the <Pay> docs.

Rate this page: