More Tutorials

3DS supported Integration with Chargebee APIs
3D Secure
Product Catalog 1.0

Tutorial Scope

This tutorial explains the steps to implement 3DS2-enabled card payments for Chargebee subscriptions using elements. The integration involves client-side implementation using Frames and sequential communication between and Chargebee APIs for the backend payment process. The sample code is provided to help you try out the integration at your end.

Frames Overview's customizable iFrame-based hosted payment form and its fields can be used to collect sensitive card details without the need to collect it at your end. Frames can be accessed using's JavaScript library.

Learn more about Frames.

Other ways to integrate: If you are looking for any other integration methods that helps you create a checkout form with easier subscription creation workflows, you can choose to integrate using:

  • Chargebee.js library - for quick and easy integration
  • Chargebee hosted pages API - for custom integration

Learn more about Chargebee checkout integrations.

Integration flow

The entire 3DS checkout flow including subscription creation is outlined as follows:

Checkout 3DS
Checkout 3DS
  1. Collect payment details

    • Users enter their card details on a checkout form built using Frames
    • Upon submission, the card information is passed to the’s server in exchange for a temporary card token. Pass this to your backend.
  2. Create Payment Request

    • Using Chargebee’s Estimate API, the estimated checkout amount is fetched from Chargebee. (Frontend/Backend)
    • A 3DS2 payment request with the amount set to $0(or actual amount for non-trial plans), containing the temporary card token, (card details) and other checkout details are submitted to This is used to verify the card and return a permanent card source Id (example src_nwd3m4in3hkuddfpjsaevunhdy) which can be used for subsequent payments thereafter.

    If immediate payment is requested by the merchant, the amount can be the actual subscription fee. In that case, a separate card verification is not required.

  3. 3DS Challenge Flow

    • If the card is enrolled for 3DS2 payments, the payment redirects to the 3DS challenge flow authentication window.
    • On successful authentication, payment status changes from “Pending” to "Authorized" or “Card Verified”. You can verify the payment status using the Get payment details API using the session ID.
  4. Create Subscription

    • Once the payment status has changed to “Authorized” or “Card Verified”, the payment Id, permanent card source Id (src_nwd3m4in3hkuddfpjsaevunhdy), along with other checkout details are passed to Chargebee using the create subscription API.
    • Chargebee captures the payment and creates the Subscription.


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

  • A Chargebee account
  • Your Chargebee test site's API key
  • Product Catalog configured in Chargebee
  •’s client library set up. Download and importthe client library of your choice and configure the client library with's test secret key.
  • Configure as a payment gateway in Chargebee.
  • Webhooks setup for notifications (Optional)

Setup Client library

Download and import the client library of your choice and configure.

For the tutorials we have configured the credentials in the constructor of the class.

CheckoutDotCom3ds.javaView full code
/* Set false for Production account */
this.api = CheckoutApiImpl.create("<>", true, "<>");
Environment.configure("<chargebee-site-name>", "<chargebee-api-key>");

Client-side Implementation

The client-side implementation of Checkout Frames and Chargebee API integration for creating a subscription in Chargebee.

Checkout form

The client-side implementation starts by building a payment form for collecting payment details (customer and card details). The sample form we've used here contains fields for customer and card information.

You need to initialize Frames for collecting payment details by authenticating using your Public key as shown below:

checkoutdotcom_3ds/frames.htmlView full code

Add the Frames JavaScript file in the header tag of the form. The frames script will relay the payment details to’s server for processing the card information and payments.

checkoutdotcom_3ds/frames.htmlView full code
<script src=""></script>

Event handler: card validation

Add the card validation event handler to listen to card validation responses from and is triggered as soon as the card details are submitted and the card validation status changes. This is done to verify whether the valid card is used for the 3DS flow.

checkoutdotcom_3ds/frames.htmlView full code
  function (event) {
    console.log("CARD_VALIDATION_CHANGED: %o", event);
    payButton.disabled = !Frames.isCardValid();

Event handler: Card Tokenization

Add the card tokenization event handler which listens to card tokenization responses and retrieves the card token. This event must be triggered as soon as the valid card details are submitted.

checkoutdotcom_3ds/frames.htmlView full code
  function (event) {
    var el = document.querySelector(".success-payment-message");
    el.innerHTML = "Card tokenization completed<br>" +
      "Your card token is: <span class=\"token\">" + event.token + "</span>";

An alpha-numeric card token is returned to the user. Now, the next step is to create a card payment.

Card tokens are single use tokens which have a lifespan of 15 minutes.

Server-side Implementation

Implementation of Chargebee’s Subscription API within the payment collection workflow for creating a subscription in Chargebee.

Step 1: Create a card payment


Before creating a card payment, ensure that:

  1. The payment status is either Authorized or Card Verified
  2. A redirect success and failure URL configured for 3DS in your Hub dashboard

Using the temporary card token generated at the time of payment creation, initiate a card payment request of $0 or actual amount that you got from the estimate API using card token using the following endpoint:

For the tutorials we have configured the credentials in the constructor of the class.

CheckoutDotCom3ds.javaView full code
/* Returns a Processed payment source. The Payment request is created */
public PaymentProcessed CreateProcessedPaymentSource(String token){
    TokenSource tokenSource = new TokenSource(token);
    PaymentRequest<TokenSource> paymentRequest = PaymentRequest.fromSource(tokenSource, Currency.USD, 10000L);
    PaymentResponse response;

    try {
        response = this.api.paymentsClient().requestAsync(paymentRequest).get();
        this.paymentSourceID = response.isPending() ? response.getPending().getId() : response.getPayment().getId();

        /* Keep checking whether the payment has been approved */
        if (response.isPending() && response.getPending().requiresRedirect()) {
        else if (response.getPayment().isApproved()){
        else if (response.getPayment().getStatus().equals("Declined")){
        else System.out.println("Unknown error occurred.");
    } catch (CheckoutValidationException e) {
    } catch (CheckoutApiException e) {
        System.out.println("Payment request failed with status code " + e.getApiResponseInfo());
        throw e;
    } catch (ExecutionException e) {
        System.out.println(" Error: " + e.getCause().toString());
    } catch (InterruptedException e) {
    } catch (IOException e) {
    } catch (URISyntaxException e) {
    return this.payment;

Learn more about creating a card payment.

Creating a payment of $0 initiates a card verification request to servers. It creates a permanent source Id (for example, src_nwd3m4in3hkuddfpjsaevunhdy) for the card for future transactions and also generates a payment “id”. You may also choose to pass the actual subscription amount as value for the “amount” field in which case, the verification happens automatically.

Step 2: 3DS challenge flow - Response

The payment response is a 202 asynchronous payment response for the 3DS challenge flow.

CheckoutDotCom3ds.javaView full code
/* Redirect the user to the Authorization Flow URL */ this.redirectURL =
paymentResponse.getPending().getRedirectLink().getHref(); Desktop.getDesktop().browse(new
  "id": "pay_y3oqhf46pyzuxjbcn2giaqnb44",
  "status": "Pending",
  "reference": "ORD-5023-4E89",
  "customer": {
    "id": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
    "email": "",
    "name": "Sarah Mitchell"
  "3ds": {
    "downgraded": false,
    "enrolled": "Y"
  "_links": {
    "self": {
      "href": ""
    "redirect": {
      "href": ""

redirect key contains the URL to which the users are redirected to follow the 3DS challenge flow. Once the user successfully completes the challenge flow, the payment status changes from “Pending” to Authorized.

Step 3: Check for Payment Status

You can enable webhooks to listen to payment status from the Get Payment Detail API response.

CheckoutDotCom3ds.javaView full code
/* Fetches the current instance of the Payment Source */
public GetPaymentResponse getPayment(){
    GetPaymentResponse checkedPayment = null;
    try {
        checkedPayment = this.api.paymentsClient().getAsync(this.paymentSourceID).get();
        System.out.println(String.format("Payment ID: %s Status: %s",checkedPayment.getId(), checkedPayment.getStatus()));
    } catch (InterruptedException | ExecutionException e) {
    return checkedPayment;

public boolean isPaymentApproved(String payment_id){
    GetPaymentResponse getPaymentResponse = getPayment();
    if (getPaymentResponse.getStatus().equals("Declined"))
    /* Check whether the payment is Authorized */
    else return getPaymentResponse.isApproved();
    return false;
  "id": "pay_jkpegpvbjviu5pu6xkewah5r6y",
  "requested_on": "2019-01-28T11:12:54Z",
  "source": {
    "id": "src_v2fgh6u6ijmehgmu5efkbgw4d4",
    "type": "card",
    "expiry_month": 8,
    "expiry_year": 2025,
    "scheme": "Dinersclub",
    "last4": "9019",
    "fingerprint": "792A3B9CCCEE7E940E41CC40E92D08E1DE48BAD0F61BAFAF3809C93270241F83",
    "bin": "301234",
    "card_type": "Credit",
    "card_category": "Commercial",
    "issuer": "US Bank",
    "issuer_country": "US",
    "product_id": "L",
    "product_type": "Commercial Credit",
    "avs_check": "S",
    "cvv_check": ""
  "amount": 6500,
  "currency": "USD",
  "payment_type": "Regular",
  "reference": "ORD-5023-4E89",
  "status": "Authorized",
  "approved": true,
  "risk": {
    "flagged": false
  "customer": {
    "id": "cus_ebxdsbvjgxcuxpkluxpwwychka"
  "billing_descriptor": {
    "name": "Fiona's Fashion",
    "city": "New York"
  "eci": "05",
  "scheme_id": "638284745624527",
  "_links": {
    "self": {
      "href": ""
    "actions": {
      "href": ""

Check for the following key value:

  • "status": "Authorized" or Card Verified
  • "approved": true

Creating a Subscription

Once the payment status is Authorized or Card Verified pass the payment_id to create a subscription using the create subscription API via payment_intent[gw_token]:

Chargebee can create a subscription only when the payment state is Authorized or Card Verified.

CheckoutDotCom3ds.javaView full code
public static String createChargebeeSubscription(String paymentMethodID) {
  Result result = null;
  try {
    result = Subscription.create()
            .billingAddressLine1("PO Box 9999")
  } catch (Exception e) {
  Subscription subscription = result.subscription();
  System.out.println(String.format("Chargebee Subscription \'%s\' created for Payment ID \'%s\'",, paymentMethodID));
  • gatewayAccountId: can be found in Payment Gateway’s details page
  • gwToken: the Session Id or payment Id returned after redirection
  • referenceId: this will be’s customer_id/source_id


ChargeBee_Subscription::create(array(<param name> => <value>,<param name> => <value> ...))

Learn more about the keys.

Once you've successfully processed the card payment request, you can simply use the source Id (src_v2fgh6u6ijmehgmu5efkbgw4d4) for subsequent payments.

Test cards

When you're all set, test your integration with some test transactions. Here are some credit card numbers that you can use to test the application:

For more test cards for testing different scenarios click here.

Was this tutorial helpful ?
Need more help?

We're always happy to help you with any questions you might have!