3DS supported Stripe.js Integration with Chargebee APIs

Watch Video

Tutorial Scope 

We will only address the flow specifics of processing your payment through 3DS using Stripe Elements, integrated through Stripe.js and Chargebee APIs. We have also included the example code and Github links to it. This way, you can try out the tutorial with our mock checkout.

Stripe.js: Overview 

Stripe.js is a JavaScript library, which is accessible via APIs to tokenize customer information by collecting sensitive card data using customizable Stripe Elements .
For further details on Stripe.js, take a look at Stripe's documentation .

Steps: Overview

Here's a detailed set of steps on how the entire 3DS checkout flow works:

  1. Create Payment Method
    • User enters their card details inside Stripe Elements.
    • On submit, Stripe.js passes the card information to the Stripe server using Create PaymentMethod request .
    • Stripe verifies the card and returns a PaymentMethod ID.
  2. Create Payment Intent
    • The PaymentMethod ID along with other checkout details are submitted to your server.
    • On your server, using Estimate API , get the estimated amount for this checkout from Chargebee.
    • Using that amount, call Stripe API to Create a PaymentIntent  on your server side.
  3. Authenticate
    • Stripe.js will show authentication window only if additional authentication is required.
    • On successful authentication, payment intent status will change to "requires capture"
  4. Create Subscription
    • Payment Intent along with other checkout details are submitted to your server.
    • These details are passed on to Chargebee's create subscription API.
    • Chargebee captures the payment using the intent and creates the subscription.

Honey Comics - Demo Application 

Honeycomics is the demo application of Chargebee for which you can download the code and create the application to test out the flow mentioned in this tutorial.

Prerequisites 

Before trying out this tutorial, you would need to setup the following:


Stripe.js + Chargebee API Integration 

This will be a walkthrough of the working implementation of Stripe.js and Chargebee API integration for creating a subscription in Chargebee.

Integrate Stripe Elements

If you haven't implemented Stripe Elements  on your checkout page, please do so. The steps mentioned here require you to have a Stripe.js integration. You can follow the steps mentioned here to integrate Stripe Elements in your checkout using Stripe.js.

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
<script src="https://js.stripe.com/v3/"></script>

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
var stripe = Stripe('pk_test_KnsIwFNro5WaA41h1qO4kNbK87N9KXBLxR');

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
<div class="row">
    <div id="card-element"></div>
</div>

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
var elements = stripe.elements();
var cardElement = elements.create('card');
cardElement.mount('#card-element');

Server-side Stripe API Integration

Stripe API Integration on your Server-side is much needed to go forward. You can choose the client library that you prefer and integrate it in your backend. More information on the integration can be found under Stripe API Integration .

Create Client-side Object: PaymentMethod 

Now, you need to write JavaScript, in a way that it should trigger up as soon as the customer submits the form and,

  • Pass the card details to Stripe
  • Handle the response from Stripe

Use stripe.createPaymentMethod('card', cardElement, {})  to pass the card details via cardElement to Stripe. The parameter cardElement should be the Stripe element used for obtaining card information.

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
stripe.createPaymentMethod('card', cardElement, {})

Handle PaymentMethod Response 

If successful, the JSON response will have PaymentMethod object . In case the card validation fails, the JSON object will contain the error information.

From the PaymentMethod object, extract its ID and pass it on to your server for creating the payment intent.

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
fetch('/stripe_js_3ds/confirm_payment', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        payment_method_id: result.paymentMethod.id,
        addr: $('[name="addr"]').val(),
        extended_addr: $('[name="extended_addr"]').val(),
        city: $('[name="city"]').val(),
        state: $('[name="state"]').val(),
        zip_code: $('[name="zip_code"]').val(),
    })
}).then(function (result) {
    // Handle server response
    result.json().then(function (json) {
        handleServerResponse(json);
    })
});


Now let's switch to the server side implementation

Setup Chargebee's Client library 

Download and import  the client library of your choice. Then, configure the client library with Chargebee Test site and its full-access API Key .

For the tutorials we have configured the site and the credentials in a properties file from which the client library is configured at the webapp is initialized.

For the tutorials we have configured the site credentials in config/environments/development.rb

We setup the client library in config/initializers/chargebee.rb

For the tutorials we have configured the site credentials in Config.php which is included in other php files.

Setup Stripe's Client library 

Stripe API Integration is necessary on your Server-side to go forward. Download and import  the client library of your choice. Then, configure the client library with Stripe's test secret key.

Create Server-side Object: PaymentIntent 

Pass the PaymentMethod ID to create a PaymentIntent  object on the Server-side. For this, you need to send a request to Stripe APIs for creating PaymentIntent object on your Server-side.

Setting confirmation

This tutorial follows manual confirmation flow. Hence, set the confirmation_method as ‘manual'.
"confirmation_method" => "manual"

Note

Chargebee APIs support both 'manual' and 'automatic' confirmation. Learn more 

The request further requires three compulsory keys to be passed while creating the PaymentIntent object:

Retrieving amount

The invoice amount that needs to be charged can be obtained by calling the Estimate API  from Chargebee. This can then be passed to the amount parameter in PaymentIntent.

Setting capture method

Make sure you change the capture_method key to manual from automatic. This way, authorization happens on your side and capture happens on Chargebee side. Learn more 
"capture_method" => "manual"

Note

The capture_method key is set to automatic by default. If not changed to manual, authorization and capture happens on your side, and Chargebee cannot charge the card.

Setting future usage

You need to set setup_future_usage as off_session, so that the PaymentIntent doesn't fail while Chargebee tries to charge the card. Learn more 
"setup_future_usage" => "off_session"

PaymentIntent Response

If the PaymentIntent response contains either one of these statuses,

  • requires_action
  • requires_source_action

It essentially means client authentication is required, which is explained in the next section.

PaymentIntent will return a client_secret_key along with the requires_action response.

Note

For PaymentIntents, API versions in Stripe before 2019-02-11 show requires_source_action instead of requires_action.


Now, let's switch to the client side implementation

User Authentication 

Using client_secret

  • You will have to pass client_secret_key to Stripe.js' stripe.handleCardAction  function.
  • Stripe.js will take care of opening the authentication window.

Confirmation

After the authentication is complete, PaymentIntent needs to be confirmed either manually or automatically depending on which of the either value was passed while creating PaymentIntent.

  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
function handleAction(response) {
    stripe.handleCardAction(
        response.payment_intent_client_secret
    ).then(function (result) {
        if (result.error) {
            // Show error in payment form
            console.log(JSON.stringify(result));
            $(".alert-danger").show().text(result.error.message);
        } else {
            // The card action has been handled
            // The PaymentIntent can be confirmed again on the server
            fetch('/stripe_js_3ds/confirm_payment', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    payment_intent_id: result.paymentIntent.id
                })
            }).then(response => response.json()).then(function (confirmResult) {
                console.log("payment_intent_id: ", confirmResult.payment_intent_id, "success: ", confirmResult.success);
                handleServerResponse(confirmResult);
            });
        }
    });
}

Payment 

  • Following confirmation, PaymentIntent status changes to requires_capture.
  • Now the PaymentIntent ID can be passed with Chargebee APIs to perform the necessary operations.
  • php
  • Ruby
  • Java
  stripe_js_3ds/checkout.html  -   View full code
fetch('/stripe_js_3ds/checkout', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        customer: {
            first_name: $('[name="customer[first_name]"]').val(),
            last_name: $('[name="customer[last_name]"]').val(),
            email: $('[name="customer[email]"]').val(),
            phone: $('[name="customer[phone]"]').val()
        },
        addr: $('[name="addr"]').val(),
        extended_addr: $('[name="extended_addr"]').val(),
        city: $('[name="city"]').val(),
        state: $('[name="state"]').val(),
        zip_code: $('[name="zip_code"]').val(),
        payment_intent_id: response.payment_intent_id,
    })
}).then(response => response.json()).then(function (responseJSON) {
    window.location.replace(responseJSON.forward);
});

Create subscription 

You can fetch the PaymentIntent ID and other information from the POST parameters submitted by your form and use the Create Subscription  API to create a subscription in Chargebee.

Redirecting to a Thankyou page

When a subscription is created successfully, Chargebee returns a success response in JSON format which is wrapped as a 'result' class by the client library.

In the event of a successful checkout you can redirect the user to a simple 'Thank You' page.

Validation and Error Handling

Here's how we validate user inputs and handle API call errors in this demo:

  • Client Side Validation: Chargebee uses jQuery form validation  plugin to check whether the user's field inputs(email, zip code and phone number) are valid or not.

  • Server Side Validation: As this is a demo application we have skipped the server side validation of all input parameters. But we recommend you to perform the validation at your end.

  • Payment Errors: If a payment fails due to card verification or processing errors, Chargebee returns an error response  which is thrown as a payment exception by the client library. We handle the exceptions in the demo application with appropriate error messages.

  • General API Errors: Chargebee might return error responses due to various reasons such as invalid configuration, bad request etc. To identify specific reasons for all error responses you can check the API documentation . Also take a look at the error handler file to check how these errors can be handled.

Test cards 

You can now test your integration with test transactions. Here are some credit card numbers that you can use to test your application.

3DS Required
4000 0000 0000 3220
3DS Supported
4000 0000 0000 3055
3DS Not Supported
3782 8224 6310 005

For more test cards for testing different scenarios click here .