More Tutorials

Payment Components Quickstart

Chargebee.js
Checkout
Payments

This quickstart guide helps you set up a JavaScript project that demonstrates Chargebee.js Payment Components.

Prerequisites

Before you start, ensure you have the following:

  • Set up payment gateways in Chargebee Billing.
  • Configure payment methods and Smart Routing, if necessary.
  • Set up the Product Catalog in Chargebee.
  • Install Node v18 or above.
  • To ensure Google Pay can complete transactions, set the permissions-policy header to payment=(*) if your site uses a permissions policy.
  • Complete the gateway prerequisites before proceeding with Apple Pay integration.

Running the sample application locally

You can download and run the sample application locally by following the instructions in its Readme on GitHub.

Code walkthrough

This section explains how the code in the quickstart sample app works.

The following diagram shows how these steps fit together across your page, your backend, Chargebee, and your payment gateway:

Sequence diagram of a payment. Your page initializes Chargebee.js, asks your backend for a payment intent, then creates and mounts the Payment Component and Payment Button Component. The component fetches eligible payment methods, the customer enters details and clicks the button, and confirm() sends the payment to Chargebee and on to the gateway. If the gateway requires authentication, Chargebee returns an in_progress payment intent with a URL and opens it for the customer. The authorized payment intent then reaches your page through onSuccess(), and your backend creates the subscription.

Load Chargebee.js (client)

Load Chargebee.js on the checkout page by adding the following script to the <head> element of the page.

client/index.htmlView full code
<script src="https://js.chargebee.com/v2/chargebee.js"></script>

Initialize Chargebee.js (client)

Once the page loads, initialize Chargebee.js with a publishable key. This creates a Chargebee object used to create components.

client/scripts/checkout.jsView full code
const chargebee = window.Chargebee.init({
   site: env.site,
   publishableKey: env.publishableKey,
})

Request a payment intent (client)

After the page loads, request your server to create a new payment_intent.

client/scripts/checkout.jsView full code
const url = "http://localhost:8082/payment-intent";
const response = await fetch(url, {
    method: "POST",
});
if (!response.ok) {
    throw new Error(`Response status: ${response.status}`);
}
const json = await response.json();

Create a payment intent (server)

Create an endpoint on your server that creates a payment_intent in Chargebee Billing.

server/server.jsView full code
app.post('/payment-intent', async (req, res) => {

    const url = `https://${env.site}.chargebee.com/api/v2/payment_intents`;
    const amount = 5000;
    const currencyCode = 'USD';
    try {
        const result = await fetch(url, {
            method: 'POST',
            headers: {
                'Authorization': 'Basic ' + btoa(`${env.apiKey}:`),
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: new URLSearchParams({
                amount: amount,
                currency_code: currencyCode
            })
        })
        const response = await result.json();
        console.log(response)
        res.status(200);
        res.send(response.payment_intent);
    } catch (error) {
        console.log(error)
        res.status(500);
        res.send(error);
    }
});

Add a div for the Payment Component (client)

Add an empty placeholder <div> element to your page as a placeholder for the Payment Component. Chargebee inserts an <iframe> into this <div> to securely collect payment information.

client/index.htmlView full code
<div id="payment-component"></div>

Create and mount the Payment Component (client)

Create a Components object and use it to create a PaymentComponent object. Mount the Payment Component to the placeholder <div>. This adds an <iframe> with a dynamic form that displays the payment methods.

You can restrict the displayed payment methods using the paymentMethods.allowed option and specify their sort order using paymentMethods.sortOrder.

The customer provides the details for the payment method and submits the form.

client/scripts/checkout.jsView full code
const componentOptions = {
    locale: "en",
    style: {
        theme: {
            accentColor: "gold",
            appearance: "light",
        },
        variables: {
            spacing: 2,
            accentIndicator: "#ffff00",
        },
    },
};

const paymentComponentOptions = {
    paymentIntent: json,
    layout: {
        type: "tab",
        showRadioButtons: true,
    },
    paymentMethods: {
        sortOrder: ["card", "paypal_express_checkout", "google_pay", "apple_pay"],
        allowed: ["apple_pay", "paypal_express_checkout", "card", "google_pay"],
    },
};

const components = chargebee.components(componentOptions);

const paymentComponent = components.create("payment", paymentComponentOptions, {
    onError,
    onSuccess,
    onPaymentMethodChange,
    onButtonClick,
    onClose,
});

paymentComponent.mount("#payment-component");

(Optional) Add a div for the payment button component (client)

Add an empty <div> element to your page as a placeholder for the payment button component.

client/index.htmlView full code
<div id="payment-button-component"></div>

The payment button component is a dynamic prebuilt UI button that submits the payment form when clicked.

(Optional) Create and mount the payment button component (client)

Use the Components object to create a PaymentButton object and mount it to the placeholder <div> created earlier.

client/scripts/checkout.jsView full code
const paymentButtonComponent = components.create(
    "payment-button",
    {},
    {
        onError,
        onClose,
    },
);
paymentButtonComponent.mount("#payment-button-component");

Chargebee inserts an <iframe> into the <div>, creating a dynamic payment button that adjusts based on the selected payment method. When the customer clicks the payment button, Chargebee manages the interaction and collects the payment.

Handle errors (client)

If there are any errors during payment collection, such as card declines, the Payment Component calls the onError() callback. Use the error object to display relevant messages to the user so they can retry or select a different payment method.

Request to create a subscription (client)

In the onSuccess() callback, request your server to create a subscription for the customer at Chargebee. The callback includes the authorized payment_intent. Pass the payment_intent.id to your server.

client/scripts/checkout.jsView full code
const onSuccess = async (payment_intent, extra) => {
 const url = "http://localhost:8082/submit";
 console.log(payment_intent, extra);
 try {
  const response = await fetch(url, {
   body: JSON.stringify({ payment_intent_id: payment_intent.id }), // Convert to JSON string
   method: "POST",
   headers: {
    'Content-Type': 'application/json' // Set the content type to JSON
   }
  });

  if (!response.ok) {
   throw new Error(`Response status: ${response.status}`);
  }
  const json = await response.json();
  console.log("checkout-complete", json);
 } catch (error) {
  console.error(error.message);
 }
}

Create a subscription (server)

Use the create subscription API, passing the authorized payment_intent.id and customer details to create a subscription in Chargebee.

server/server.jsView full code
const createSubscriptionUri = `https://${env.site}.chargebee.com/api/v2/customers/` + customer.id + '/subscription_for_items';
const createSubscriptionResult = await fetch(createSubscriptionUri, {
    method: 'POST',
    headers: {
        'Authorization': 'Basic ' + btoa(`${env.apiKey}:`),
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
        'subscription_items[item_price_id][0]': 'Non-Zero-Dollar-Plan-USD-Monthly',
        'subscription_items[quantity][0]': '1',
        'payment_intent[id]': paymentIntentId
    })
})

Test the 3D Secure challenge

Payment Components run 3D Secure (3DS) internally, so there is no extra code to test. To see the challenge, force one with a test card:

  1. Configure your gateway in a Chargebee test site using the gateway's own test or sandbox credentials.
  2. Enable 3DS at both the gateway and Chargebee.
  3. Select Card in the Payment Component and pay with one of your gateway's 3DS test cards. For example, see the test cards for Stripe or Braintree. Each gateway publishes its own set, as noted in Integrations and impacts.

Chargebee opens the challenge for the customer to complete. As the payment progresses, the payment_intent.status moves from inited through in_progress to authorized, and your onSuccess() callback then fires with the authorized payment_intent. If authentication fails, onError() fires instead.

Next steps

Check out Payment Components use cases for more scenarios using Payment Components.

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.