# Quickstart

Early Access

The Payment Components feature is in early access. To request access, write to eap@chargebee.com.

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:

# Running the sample application locally

You can download and run the sample application (opens new window) locally by following the instructions in its Readme on GitHub (opens new window).

# Code walkthrough

This section explains how the code in the quickstart sample app (opens new window) works.

# Load Chargebee.js (client)

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

<script src="https://js1.chargebee.com/v2/chargebee.js"></script>
1

See on GitHub: /client/index.html (opens new window)

# Initialize Chargebee.js (client)

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

const chargebee = window.Chargebee.init({
   site: env.site,
   publishableKey: env.publishableKey,
})
1
2
3
4

See on GitHub: /client/scripts/checkout.js (opens new window)

# Request a payment_intent (opens new window) (client)

After the page loads, request your server to create a new payment_intent (opens new window).

Payment Intent

A payment_intent is required to manage the payment session for your customer. It tracks the status of the payment status, recording failed attempts, and avoiding duplicate charges.

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();
1
2
3
4
5
6
7
8

See on GitHub: /client/scripts/checkout.js (opens new window)

# Create a payment_intent (server)

Create an endpoint on your server that creates (opens new window) a payment_intent in Chargebee Billing.

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);
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

See on GitHub: /server/server.js (opens new window)

# 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.

<div id="payment-component"></div>
1

See on GitHub: /client/index.html (opens new window)

# 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.

const components = chargebee.components({});
const onSuccess = (payment_intent) => {
   console.log(payment_intent);
}
const onError = (error) => {
   // handle payment errors here
   console.log(error);
}
const onPaymentMethodChange = (error) => {
   // handle payment errors here
   console.log(error);
}
const paymentComponentOptions = {
   paymentIntentId: json.id,
   layout: {
       type: 'tab',
       showRadioButtons: true,
   },
   paymentMethods: {
       sortOrder: [ "card","paypal_express_checkout","google_pay"],
       allowed: ["paypal_express_checkout", "card", "google_pay"]
   },
   locale: "fr",
   style: {
       theme: {
           accentColor: "gold",
           appearance: "light"
       },
       variables: {
           spacing: 2,
           accentIndicator: "#ffff00",
       }
   },
}
const paymentComponent = components.create(
   'payment',
   paymentComponentOptions,
   {
       onError,
       onSuccess,
       onPaymentMethodChange
   },
);
paymentComponent.mount("#payment-component");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

See on GitHub: /client/scripts/checkout.js (opens new window)

# (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.

<div id="payment-button-component"></div>
1

See on GitHub: /client/index.html (opens new window)

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

Optional component

The payment button component is recommended but optional. Alternatively, you can implement your own payment button.

# (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.

const paymentButtonComponent = components.create(
   'payment-button',
   {},
   {onError},
);
paymentButtonComponent.mount("#payment-button-component");
1
2
3
4
5
6

See on GitHub: /client/scripts/checkout.js (opens new window)

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 (e.g., 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 (opens new window). Pass the payment_intent.id (opens new window) to your server.

const onSuccess = async (payment_intent) => {
    const url = "http://localhost:8082/submit";
    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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

See on GitHub: /client/scripts/checkout.js (opens new window)

Using webhooks

Use webhooks (opens new window) for production use, instead of making the subscription request from the client-side, it's more secure and reliable to respond to webhooks from Chargebee on the server-side. Listen to the payment_intent_updated (opens new window) event via webhooks and create the subscription when the payment_intent.status (opens new window) is authorized.

# Create a subscription (server)

Use the create subscription API (opens new window), passing the authorized payment_intent.id, and customer details to create a subscription in Chargebee.

        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
            })
        })
1
2
3
4
5
6
7
8
9
10
11
12
13

See on GitHub: /server/server.js (opens new window)