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-policyheader topayment=(*)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:
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://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.
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.
A payment_intent is required to manage the payment session for your customer. It tracks the status of the payment, records failed attempts, and avoids 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();
Create a payment intent (server)
Create an endpoint on your server that creates 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);
}
});
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>
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 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.
<div id="payment-button-component"></div>
The payment button component is a dynamic prebuilt UI button that submits the payment form when clicked.
The payment button component is optional. You can implement your own custom button. However, if you choose not to use Chargebee's payment button component, Chargebee renders payment buttons for all wallet-based payment methods selected by the user.
(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,
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)
Use webhooks for production use. Instead of making the subscription creation request from the frontend, it is more secure and reliable to respond to webhooks from Chargebee on the backend. Listen to the payment_intent_updated event via webhooks and create the subscription when the payment_intent.status is authorized.
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.
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.
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:
- Configure your gateway in a Chargebee test site using the gateway's own test or sandbox credentials.
- Enable 3DS at both the gateway and Chargebee.
- 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.
We're always happy to help you with any questions you might have! Click here to reach out to us.