More Tutorials

UPI integration with Chargebee.js

Payment Method Helper
Chargebee.js
Payments

UPI (Unified Payments Interface) is a payment method that allows customers to complete online payments using their bank credentials. It is one of the preferred online payment methods in India.

This tutorial shows you how to integrate Chargebee.js with UPI (mandates) on your website and create a subscription after checkout.

Supported gateways

UPI mandates are supported by the following gateways in Chargebee:

Prerequisites

Before you begin, follow these steps:

  1. Configure the gateway settings:

  2. Ensure that Smart routing is configured to select the appropriate gateway for UPI payments.

Set up Chargebee.js

Include the Chargebee.js script on your page and initialize a Chargebee instance before you start. For the script tag, the Chargebee.init options, and the tearDown() caveat, see Set up Chargebee.js.

Create a payment intent

Create the payment intent on your server using the Create a payment intent API, then return it to the client. The payment method handler uses the payment intent internally to perform authorization.

Call your backend to fetch the payment intent (client)

function createPaymentIntent() {
  return fetch('/payment-intents', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      amount: 500,
      currency_code: 'INR',
      payment_method_type: 'upi'
    })
  }).then(function(response) {
    return response.json();
  }).then(function(responseJson) {
    return responseJson.payment_intent;
  });
}

Call Chargebee API to create a payment intent (server)

Create a payment intent using the Create Payment Intent API:

curl https://{site}.chargebee.com/api/v2/payment_intents \
  -u {fullaccess_api_key}: \
  -d amount=500 \
  -d currency_code=INR \
  -d payment_method_type=upi

Load the UPI payment method and start the payment flow

Load UPI payment method (client)

Load the UPI integration using the load() method:

chargebee.load('upi');

Set payment intent (client)

After loading the UPI handler, set the payment intent using setPaymentIntent():

chargebee.load('upi').then((upiHandler) => {
  return createPaymentIntent().then((intent) => {
    upiHandler.setPaymentIntent(intent);
  });
});

(Optional) Fetch and display the list of UPI Apps

Optionally, retrieve the list of supported UPI apps for user's device using fetchUpiInstalledAppList(), render it, and let the user select the UPI app.

chargebee.load('upi')
.then((upiHandler) => {
  return createPaymentIntent().then((intent) => {
    upiHandler.setPaymentIntent(intent);
    return upiHandler.fetchUpiInstalledAppList();
  });
})
.then((upiAppList) => {
  // Display list of supported UPI Apps.
  // Call `upiHandler.handlePayment()` with the `paymentInfo.upi_app` parameter set to the selected `upiAppList[i].id`.
});

Handle payment (client)

Call handlePayment() with the paymentInfo argument containing customer details and gateway-specific information.

Razorpay

For Razorpay, you can either let Chargebee handle the UPI flow or, optionally, let the user select the UPI app. The latter is applicable only for mobile web browsers (Android or iOS).

Option 1: Let Chargebee handle the UPI flow

This is the simplest way that works for both desktop web and mobile web browsers.

const paymentInfo = {
  customer: {
    firstName: 'John',
    lastName: 'Kennedy',
    email: 'john@abc.com',
    phone: '9999999999'
  },
  additionalData: {
    paymentType: 'recurring',
    planId: 'pro_plan'
  }
};

chargebee.load('upi')
  .then((upiHandler) => {
    return createPaymentIntent().then((intent) => {
      upiHandler.setPaymentIntent(intent);
      return upiHandler.handlePayment(paymentInfo);
    });
  })
  .then((intent) => {
    // Payment intent is `authorized`.
    return createSubscription(intent.id);
  })
  .catch((err) => {
    console.error('Payment failed:', err);
  });
Option 2: Let the user select the UPI app

For mobile web browsers (Android or iOS), you can let the user select the UPI app from the list of supported UPI apps.

chargebee.load('upi')
  .then((upiHandler) => {
    return createPaymentIntent().then((intent) => {
      upiHandler.setPaymentIntent(intent);
      return upiHandler
        .fetchUpiInstalledAppList()
        .then((upiAppList) => ({ upiHandler, upiAppList }));
    });
  })
  .then(({ upiHandler, upiAppList }) => {
    // Display upiAppList in UI; user selects an app (e.g. upiAppList[0]).
    const selectedAppId = upiAppList[0].id; // e.g. 'gpay'
    const paymentInfo = {
      customer: {
        firstName: 'John',
        lastName: 'Kennedy',
        email: 'john@abc.com',
        phone: '9999999999'
      },
      upi_app: selectedAppId, // Only for Razorpay and mobile web (Android or iOS)
      additionalData: {
        paymentType: 'recurring',
        planId: 'pro_plan'
      }
    };
    return upiHandler.handlePayment(paymentInfo);
  })
  .then((intent) => {
    // Payment intent is `authorized`.
    return createSubscription(intent.id);
  })
  .catch((err) => {
    console.error('Payment failed:', err);
  });

dLocal

For dLocal, Chargebee handles the UPI flow on calling handlePayment() with the appropriate arguments.

const paymentInfo = {
  customer: {
    firstName: 'John',
    lastName: 'Kennedy',
    email: 'john@abc.com',
    phone: '9999999999'
  },
  additionalData: {
    paymentType: 'recurring',
    document: {
      type: 'in_pan',
      number: 'ABCDE1234F' // Valid Indian PAN
    },
    shippingAddress: {
      addressLine1: '123 Main Street',
      addressLine2: 'Apartment 4B',
      city: 'Mumbai',
      state: 'Maharashtra',
      stateCode: 'MH',
      countryCode: 'IN'
    }
  }
};

chargebee.load('upi')
  .then((upiHandler) => {
    return createPaymentIntent().then((intent) => {
      upiHandler.setPaymentIntent(intent);
      return upiHandler.handlePayment(paymentInfo);
    });
  })
  .then((intent) => {
    // Payment intent is `authorized`.
    return createSubscription(intent.id);
  })
  .catch((err) => {
    console.error('Payment failed:', err);
  });

On successful authorization, the status of payment_intent changes to authorized, and Chargebee redirects the user back to your website (payment authorization page).

Create a subscription

Call your backend to create a subscription (client)

After the payment intent is authorized, call your backend to create a subscription using the payment intent ID and subscription details:

function createSubscription(paymentIntentId) {
  return fetch('/subscriptions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      paymentIntentId,
      plan_id: 'pro_plan',
      plan_quantity: 1,
      billingAddress: {
        // Add billing address details.
      },
      customer: {
        // Add customer details if the subscription is to be created for an existing customer.
      }
    })
  }).then(response => response.json());
}

Create a subscription (server)

Pass the ID of the successfully authorized payment_intent to Chargebee's Create a subscription API.

curl  https://{site}.chargebee.com/api/v2/customers/__test__8asz8Ru9WhHOJO/subscription_for_items \
     -X POST \
     -u {site_api_key}: \
     -d payment_intent[id]="{payment_intent_id}" \
     -d subscription_items[item_price_id][0]="pro_plan" \
     -d subscription_items[quantity][0]=1
Was this tutorial helpful ?
Need more help?

We're always happy to help you with any questions you might have! Click here to reach out to us.