Collecting Card Details Using Xendit.js

This tutorial explains how to use HTML and Xendit.js, our foundational JavaScript library, to collect card details and perform tokenization. There are three(3) steps to collecting card details:

  1. Collecting card information with Xendit.js
  2. Converting those card details to a single-use token
  3. Submitting that token, with the rest of your form, to your server

The above steps assume you have a typical HTML payment form, with a span for displaying error messages returned by Xendit.js. For an example, here is a sample form that includes basic error checking to ensure valid responses from the user, and a span to display any errors back to the user for them to take action.

Step 1: Collect Card Information

To securely collect card information, include Xendit.js in your page by putting this code into the <head> section of your website. Note that Xendit.js should be loaded from the CDN and not locally:

<script type="text/javascript" src=""></script>
<script type="text/javascript">

Your publishable API key identifies your website to Xendit during communications. Replace it with your actual Public API key to test this code through your Xendit account.

When you're ready for production, be sure to change from your Test Public API Key to your Live Public API Key.

Step 2: Validate the Card Information

Before calling the createToken method, ensure that the card data is validated. Xendit.js provides methods that can be used to validate the card number, the expiry date, and the CVN. Please see example usage of those methods below:

Xendit.card.validateCardNumber('4000000000001091'); // true
Xendit.card.validateCardNumber('abc'); // false

Xendit.card.validateExpiry('09', '2017'); // true
Xendit.card.validateExpiry('13', '2017'); // false

Xendit.card.validateCvn('123'); // true
Xendit.card.validateCvn('aaa'); // false

Step 3: Create a Single-Use Token

For security, the user’s card information never passes through your servers. Instead, the card information is ‘tokenized’ in their browser, and that token is what you need to charge the card. So, this second step is to convert the card details into a single-use representative token. This is done by pausing the form's submission and passing the card details directly to Xendit (from the user's browser).

After the javascript code where setPublishableKey was called, create an event handler that handles the submit event on the form. The handler should send the form data to Xendit for tokenization and prevent the form's submission (the form will be submitted by JavaScript later). Here is some sample code illustrating how this can be done. While this example uses jQuery, Xendit.js has no external dependencies. You can use vanilla JavaScript if you'd rather.

$(function() {
    var $form = $('#payment-form');
    $form.submit(function(event) {
        // Disable the submit button to prevent repeated clicks:
        $form.find('.submit').prop('disabled', true);
        // Request a token from Xendit:
            amount: $form.find('#amount').val(),
            card_number: $form.find('#card-number').val(),
            card_exp_month: $form.find('#card-exp-month').val(),
            card_exp_year: $form.find('#card-exp-year').val(),
            card_cvn: $form.find('#card-cvn').val()
            is_multiple_use: false,
            should_authenticate: true
        }, xenditResponseHandler);
        // Prevent the form from being submitted:
        return false;

The most important line is the call to Xendit.card.createToken. The first argument is the card details. This must be provided as individual members of a generic object.

The second argument, xenditResponseHandler, is a callback you will need to write that handles the response from Xendit. The handler accepts two arguments:

  • err is an error object which has information about failures
  • response contains the data that will be used to make a charge later

Response has the following format:

    "id": "583733d0320b64b636258a99", // Token identifier
    "status": "IN_REVIEW", // Token identifier status
    "failure_reason": "", // Token identifier failure reason
    "payer_authentication_url": "", // URL where your customer can perform 3DS verification

When your script receives the response from Xendit's servers, the xenditResponseHandler function is called:

  • If the card information entered by the user returned an error, the error gets displayed on the page
  • If no errors were returned—a single-use token was created successfully, add the returned token identifier to the form and submit the form to your server

To get the token to your server, it's stored in a new hidden input. Its value is the received token's ID.

Some cards require an additional level of authentication known as 3D Secure (3DS) or OTP (one-time password). For your website to support these cards, it must be able to render the 3DS verification screen where the user can enter their OTP. This 3DS verification screen must be opened in the same window, either in a modal or an iframe (iframes are more common).

It is important to ensure that:

  • If the user refreshes on the 3DS page (or closes a 3DS pop-up modal), they are returned to the page where they entered card information.
  • When the 3DS process is completed, the iframe or modal is closed and the user is directed to your success or error page, depending on the result.

If the user's card requires 3DS, the status will be IN_REVIEW and there will be a field named payer_authentication_url. You will need to send your customer to this URL so they can enter their 3DS details. The URL has to be opened in the same page using a modal or an iframe, and not in another browser tab or window.

Additionally, when 3DS completes or fails, the same callback function, xenditResponseHandler, will be called with the updated token identifier information.

Below is a full example of xenditResponseHandler, including opening a new iframe for 3DS verification:

function xenditResponseHandler (err, creditCardToken) {
    if (err) {
        // Show the errors on the form
        $('#error pre').text(err.message);
        $form.find('.submit').prop('disabled', false); // Re-enable submission


    if (creditCardToken.status === 'VERIFIED') {
        // Get the token ID:
        var token =;

        // Insert the token into the form so it gets submitted to the server:
        $form.append($('<input type="hidden" name="xenditToken" />').val(token));

        // Submit the form to your server:
    } else if (creditCardToken.status === 'IN_REVIEW') {, 'sample-inline-frame');
    } else if (creditCardToken.status === 'FAILED') {
        $('#error pre').text(creditCardToken.failure_reason);
        $form.find('.submit').prop('disabled', false); // Re-enable submission

Collecting Card Details Using Mobile SDK

Steps to use our mobile SDKs can be found in:

  1. Android
  2. iOS

Tokenization API Reference

For full API reference you can check our API Reference.

Next Steps

Last Updated on 2023-09-12