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.
In this tutorial you will learn how to:
- Create a Stripe account
- Configure a Stripe Pay Connector
- Use the <Pay> verb to capture and charge a credit card
- Write a call-back function and tell the customer if payment was successful
- Buy a Twilio phone number
- 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.
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.
Navigate to the Twilio Voice Settings Console Page and Enable PCI Mode, opt-in to Twilio's Terms of Service and click SAVE.
Navigate to Pay Connectors under Voice > Manage > Pay Connectors in the left navigation pane and click on the Stripe tile.
Click on Install.
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.
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.
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.
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:
- The user's 16-digit credit card number
- The expiry date for the credit card
- The zip code tied to the credit card account
- 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>
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.
Great! Let's create our call-back function now.
Create a Twilio Function to handle Payments
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:
- Navigate to the Functions home in your console.
- Click on the red plus icon to create a new Function.
- Select "blank" for your functions template and click "Create"
- Rename your function to "pay" and update the path to
/pay
. This will be the URL that hosts this code for you. - Select 'Incoming Voice Calls" as your event.
- 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); };
- Save your Function. This action fully deploys your Function.
- 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>
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.
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.
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:
- Enter text 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
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.
You can navigate over to your Stripe Dashboard, copy the “PaymentConfirmationCode” “ch_xxxxx,” and paste into the Stripe search. You should see the following:
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 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 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>.
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 by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.