Menu

Rate this page:

Thanks for rating this page!

We are always striving to improve our documentation quality, and your feedback is valuable to us. How could this documentation serve you better?

How to capture your first payment using <Pay>

In under five minutes, you will learn how to build an IVR that captures payment details and charges a credit card using Twilio's <Pay> TwiML verb and Stripe.

The TwiML <Pay> verb captures your customer's payment details. Twilio <Pay> Connectors tokenize and charge credit cards using your preferred Payment Provider. For this tutorial, we'll use Stripe to charge a credit card.

pay-diagram-1-final.png

In this tutorial you will learn how to:

  1. Create a Stripe account
  2. Configure a Stripe <Pay> Connector
  3. Use the <Pay> verb to capture and charge a credit card
  4. Write a call-back function and tell the customer if payment was successful
  5. Buy a Twilio phone number
  6. Test capturing credit card details and see the resulting charge on your Stripe account

Create a Stripe Account

<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.

Sign up for a Stripe account

Configure Stripe <Pay> Connector

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. This is an easy one-step effort shown below.

<Pay> Connectors are in BETA.

Navigate to the Twilio Voice Settings Console Page and Enable PCI Mode, opt-in to Twilio's Terms of Service and click SAVE.

voice-settings-pci-mode-2.png

Navigate to <Pay> Connectors under Programmable Voice and click on the Stripe tile.

pay-connectors

Click on Install.

install-stripe-connector

Now set the Stripe Connector unique name to Default. 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.

Change Stripe unique name to default

Now we are ready for you to authorize Twilio to make charges and tokens on your behalf.

Click on "Connect with Stripe" which will redirect over to Stripe and ask you to enter your credentials. At the end, your Stripe account will be connected with the Twilio Stripe Connect Platform.

Click Connect with Stripe

5-connect-stripe-com.png

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 simply click the link at the top "Skip this account form". You will be redirected back to Twilio now.

connected-try2.png

Notice the Stripe account ID (acct_xxxxxx) is shown. In case you have multiple Stripe accounts for DEV/STAGE/PROD, showing the Stripe account ID helps you associate the <Pay> Connector instance with the correct Stripe account.

That's all for configuring <Pay> Connectors! Now let's move on to the <Pay> TwiML verb that captures the payment details.

Set up Twilio <Pay> to capture payment details

With a small amount of TwiML, <Pay> will capture the four pieces of payment details needed to create a charge on a credit card. Those are:

  1. The user's 16-digit credit card number
  2. The expiry date for the credit card
  3. The zip code tied to the credit card account
  4. The CVC security code with retries built-in.

To learn about possible customizations for Pay, please see the <Pay> documentation.

We'll leverage Twilio's TwiML Bins to write the code that will handle collecting your customers' payment details. Head over to TwiML Bins in your console. Click on the red plus icon to create a new bin.

Give your new TwiML Bin a friendly name of "<Pay> with Stripe", then enter the following TwiML:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Calling Twilio Pay</Say>   
  <Pay chargeAmount="20.45"/>
</Response>
Loading Code Sample...
      
      
      
      
      Collect payment details for a specific amount.

      Charge a specific amount

      Collect payment details for a specific amount.

      When <Pay> completes capturing our user's credit card, it will initiate a transaction with Stripe and then send some information via webhook to a specified call-back action URL.

      We'll write this call-back function next leveraging Twilio Functions (though you could use any publicly accessible URL for this).

      For now, save your TwiML bin and copy the URL it provisions for you.

      Copy the URL for your new TwiML bin

      Great! Let's create our call-back function now.

      Create a Twilio Function to handle <Pay>ments

      When <Pay> completes capturing the consumers’ credit card the <Pay> Connector will initiate a transaction with the Payment Provider. Next, it will webhook to the specified call-back action URL with a status returned. Let’s write this call-back function next.

      We'll leverage Twilio's Functions to write and host this code. Functions are Twilio’s serverless solution allowing you to deploy javascript-based applications.

      You can customize your call-back code to personalize the experience for your customers. For this tutorial, we'll look at the status after <Pay> completes. The function could be extended to also look at the PaymentError attribute which contains the status Stripe sent back for the user's payment method.

      To create this Function:

      1. Navigate to the Functions home in your console.
      2. Click on the red plus icon to create a new Function.
        Create a new function
      3. Select "blank" for your functions template and click "Create"
        Create a function from a blank template
      4. Rename your function to "pay" and update the path to /pay. This will be the URL that hosts this code for you.
      5. Select 'Incoming Voice Calls" as your event.
        Build a function to handle payments
      6. Now you can remove the boilerplate code and paste the following code into your Function:
        exports.handler = function(context, event, callback) {
            console.log("in Pay");
            console.log(event);
            console.log(event.Result);
            
        	let twiml = new Twilio.twiml.VoiceResponse();
        	
        	switch (event.Result) {
            case "success":
                text = "Thank you for your payment";
                break;
            case "payment-connector-error":
                text = "The Payment Gateway is reporting an error";
                console.log(decodeURIComponent(event.PaymentError));
                break;
            
            default: 
                text = "The payment was not completed successfully";
        }
        	twiml.say(text);
        	callback(null, twiml);
        };
        
      7. Save your Function. This action fully deploys your Function.
      8. Copy the URL for your new Function, then head back to the TwiML bin you created in the last step.

      Now, update your code to include your Function URL in the action parameter.

      Your TwiML code should look like this now:

      <?xml version="1.0" encoding="UTF-8"?>
      <Response>
        <Say>Calling Twilio Pay</Say>
        <Pay chargeAmount="20.45" 
          action="https://enter-your-callback-function-url.twil.io/pay"/>
      </Response>
      
      Loading Code Sample...
          
          
          
          
          Set a callback URL and collect payment details for a specific amount.

          Receive a <Pay> callback

          Set a callback URL and collect payment details for a specific amount.

          Save your TwiML bin. Now it's time to connect a phone number to your new Pay application.

          Purchase a voice-enabled Twilio phone number

          In the Twilio console, search for and purchase an available phone number capable of voice calls.

          Purchase a voice-enabled phone number from Twilio

          Now that you have a phone number in hand, you need to tell it where to find your <Pay> application for managing calls. Click on "set up number" (or if using an owned Twilio phone number, click it in your list of phone numbers.)

          Scroll to the "Voice & Fax" section. Double-check that "Accept Incoming" is set to Voice Calls, and Configure With is set to "Webhooks, TwiML Bins...".

          Next to "A call comes in", select "TwiML" from the drop-down. You'll then be able to select the TwiML bin you made earlier.

          Connect your TwiML bin to your phone number

          Save your changes – it's time to test!

          Test your application

          To test out your new <Pay>-powered application, call the phone number you purchased above.

          When prompted, enter the following test values:

          1. Enter text Credit card number: 4242 4242 4242 4242
          2. Expiry date (MM/YY): 12 20 (pick a date in the future)
          3. Zip code: 94105
          4. CVC security code: 333

          To verify that your application correctly captured this data, navigate to your Call Logs 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

          You can navigate over to your Stripe Dashboard, copy the “PaymentConfirmationCode” “ch_xxxxx,” and paste into the Stripe search. You should see the following:

          Verify the payment via Stripe

          Troubleshooting

          If you use a Twilio Function to handle the Action call-back, then you can add the line console.log(event); in your code. This will print out the request parameters in the Log to let you inspect the contents.

          Alternatively, you can navigate to your Call Logs in the console and view the call in more detail.

          You will notice a POST request for the Action call-back 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. A failed call will show in the Result field a hint for the cause of the error.

          Possible results include:

          • too-many-failed-attempts
          • payment-connector-error
          • caller-interrupted-with-star
          • caller-hung-up
          • validation-error
          • internal-error

          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 text 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 of test cards.

          If you want a POST request after each payment detail is collected, then you can specify a status callback in <Pay>.

          Where to next?

          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 our docs for TwiML <Pay>.

          Tim Beyers Paul Kamp Kat King Kevin Whinnery

          Need some help?

          We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

          Loading Code Sample...