Checkout SDK

Checkout SDK — a set of tools for integrating payment functionality on the frontend.

SDK integration
Before we started working with the SDK please make sure
  • You passed parentUrl when creating order. This is required to redirect to correct page after user passes 3DS check. It can be done like this:
const createdOrderResponse = await fetch(GET_CHECKOUT_URL_API, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    // !!! Important !!!
    // pass parentUrl in metadata, so we can restore the payment session
    metaData: {
      parentUrl: window.location.href,
      // ...any of your analytics or session-related data
    },
    // ...product, buyer, shop etc
  }),
});

GET_CHECKOUT_URL_API along with more details on this request can be found on either Create order or One-time payment depending on your use-case.

  1. All DNS records provided by our Merchant manager were set correctly. Otherwise you’d get DNS_PROBE_FINISHED_NXDOMAIN error.
Attach a script

Add the SDK script to your HTML document:

 <script src="https://{ENVIROMENT}/checkout-sdk.umd.js"></script>

ENVIRONMENT values:

  1. SANDBOX - checkout-sdk-sandbox.billerbase.com
  2. PROD - checkout-sdk.billerbase.com

Please make sure the script is loaded before you try to run the code below.

Init SDK

The initCheckoutSDK function is used to initialize the SDK. It configures all required subscriptions, event handlers, and settings for working with the checkout.

1const CheckoutSDK = initCheckoutSDK({
2  // you get this from the request with which you create the order
3  checkoutUrl: 'https://cart.example.com/initial-billing/${orderId}',
4  debug?: {
5    logLevel: 'info',
6    logCheckoutEvents: true,
7  },
8});
Parameters
checkoutUrl (required):

A link to the checkout page received from billing when creating an order (/api/v2/initials/url).

  • You can add the query parameter priceCalculationType with the values daily | weekly | monthly | none to checkoutUrl to change how prices are displayed on the checkout.

    Example: https://cart.example.com/initial-billing/${orderId}?priceCalculationType=monthly
debug (optional):
  • logLevel ('info' | 'warn' | 'error'):
    - 'info': logs errors, warnings, and low-priority messages that may be useful during integration or debugging;
    - 'warn': warnings and errors only;
    - 'error': errors only.

    Default: 'warn'.
  • logCheckoutEvents (boolean): enables logging checkout events to the browser console.

    Default: false.
Notes
  1. Currently, a single SDK instance can create only one checkout. If you need multiple checkouts on the same page, create a separate instance for each. Each instance works independently and their events are isolated.
  2. You will receive the checkoutUrl value when you perform the request to create an order
Setup event listeners

When the script is loaded and Checkout SDK instance initiated you should subscribe to events from checkout so you can react to what’s going on inside the checkout.

Let’s continue with code example! (you could probably copy it as a starter)

CheckoutSDK.checkout.events.subscribe('ready', (payload) => {
  // means checkout form is completely loaded and ready to be used
});

CheckoutSDK.checkout.events.subscribe('submitButtonLoading', (payload) => {
  // THIS EVENT IS ONLY NEEDED WHEN YOU HAVE CUSTOM SUBMIT BUTTON INSTEAD OF BUILT-IN
  // 
  // sometimes we need to block submit button so we can check the data
  // and this event is specifically for that
  // so here you should do something like
  //
  // setSubmitButtonLoading(payload.isLoading)
});

CheckoutSDK.checkout.events.subscribe('redirect', (payload) => {
  // checkout will prompt you to redirect user for such cases:
  // 1. successful payment - redirectUrl will be equal to MERCHANT_REDIRECT_URL you specified before
  // 2. 3DS - redirect to provider so user can pass the challenge and confirm the payment
  // 3. 404|503 error

  if (payload.shouldOpenInNewTab) {
    window.open(redirectUrl, '_blank');
  } else {
    window.location.href = redirectUrl;
  }
});

CheckoutSDK.checkout.events.subscribe('submit', (payload) => {
  if (payload.validationPassed) {
    // submit attempt like this will start payment processing
  } else {
    // something wrong with user's input
  }
});

CheckoutSDK.checkout.events.subscribe('paymentProcessingStart', (payload) => {
  // buckle up, we got all we needed and started payment processing
});

CheckoutSDK.checkout.events.subscribe('paymentProcessingFinish', (payload) => {
  if (payload.status === 'success') {
    // congrats! 🎉 
    // change UI to let your user know the payment is completed
    // if only change you plan is redirect, better do it in 'redirect' event handler
  } else {
    // payment processing failed (either decline or some tech error)
    // it's probably a good idea to check payload?.reason for details
  }
});

CheckoutSDK.checkout.events.subscribe('error', (payload) => {
  // catch runtime errors from sdk
});
Restoring payment session after 3DS

3DS is a mechanism when provider check if its actually the right user wants to make the payment and commonly for us it means redirect to a provider’s page.

Checkout page => Provider => Billerix => Checkout page

  1. Redirect to a provider so user can pass the check
  2. Provider sends user to our page as we have initialed the check
  3. We redirect user back to your Checkout page

But there's a pitfall: when user is directed to 3DS (step 1) the session is broken because for some time they will be on page we can’t control. So in order to restore it on step 3 we redirect user back to your Checkout page with orderId param in query, so you can check it and restore Checkout SDK instance using respectful url.

From your side it requires something like this:

1// after getting checkoutUrl
2const orderId = new URL(checkoutUrl).pathname.split('/').pop();
3localStorage.setItem(`checkoutUrl-${orderId}`, checkoutUrl);
4
5// and before every creation of order check if this visit isn't the case when user is coming back from 3DS
6const params = new URLSearchParams(window.location.search);
7const isUserComingBackFrom3DS = params.has("orderId");
8if (isUserComingBackFrom3DS) {
9  // restore session like they never left
10  const orderId = params.get('orderId');
11  const checkoutUrl = localStorage.getItem(`checkoutUrl-${orderId}`);
12  const CheckoutSDK = initCheckoutSDK({
13    checkoutUrl,
14    // ...other things you usually pass
15    },
16  });
17} else {
18  // now we know it's a new user, so here you should create an order and continue as usual
19}

There’s more about checkout events along with TS types for payload in the table below, but this is a great starter!

SDK methods
1. checkout.mount

The checkout.mount method is used to add the checkout into the specified DOM container.

1CheckoutSDK.checkout.mount({
2  containerId: 'checkout-container',
3  options: {
4    coupon: "COUPON123",
5    language: "en",
6    autocharge: false,
7  }
8});
Parameters
containerId (required):

The ID of the DOM element where the checkout will be mounted. The container must exist in the DOM before calling the method. The checkout will automatically adjust its height to content changes, so the container should be allowed to grow in height and width to avoid unwanted scrollbars.

options (optional):

A set of parameters applied when loading the checkout

  • coupon (string)
  • language (string)
  • autocharge (boolean)
  • mobileView (boolean)
    - force-enable the mobile layout; otherwise, device detection is based on userAgent;
    - may be useful if your desktop container width for the checkout matches the mobile layout width.
  • hideFields (object)
    - An object with fields to hide on the form when rendering the checkout. Currently, only the email field is supported.
    - Use the field name as the key and a boolean as the value: true — the field will be hidden; false — the field will be visible (default behavior).
2. checkout.unmount

The checkout.unmount method removes the checkout from the DOM. Event subscriptions related to it remain.

CheckoutSDK.checkout.unmount();
3. checkout.submit

The checkout.submit method is used to submit the form in the checkout. Needed when you have a custom Submit button outside the checkout.

CheckoutSDK.checkout.submit();
Notes
  1. This method triggers the submit of the checkout form;
  2. Before calling the method, make sure the checkout is mounted and ready.
4. checkout.update

The checkout.update method is used to modify checkout data.

1CheckoutSDK.checkout.update({
2  language: "de",
3  autocharge: false,
4  hideFields: {
5    email: true,
6  },
7});
Parameters
language (string)

Changes the language.

autocharge (boolean)

Enables or disables automatic subscription renewal.

hideFields (object)

An object with fields to hide on the form when rendering the checkout. Currently, only the email. Use the field name as the key and a boolean as the value: true — the field will be hidden; false — the field will be visible (default behavior).

5. checkout.events

The checkout.events object provides methods for working with checkout events. You can subscribe to events coming from the checkout.

5.1. checkout.events.subscribe

The subscribe method is used to subscribe to events coming from the checkout.

1const subscription = CheckoutSDK.checkout.events.subscribe(
2  'ready', // Event name
3  (payload) => {
4    console.log('Checkout event:', payload); // Event payload handling
5  }
6);
Parameters
type (string)

The name of the event to subscribe to. See the table “Available events”.

handler (function)

A function that will be called when the event is received, with the payload object as an argument.

Returns

An object with an unsubscribe method that allows you to cancel the event subscription.

subscription.unsubscribe();
5.2. checkout.events.unsubscribeAll

The unsubscribeAll method is used to remove all subscriptions to checkout events.

CheckoutSDK.checkout.events.unsubscribeAll();
Notes
  1. Use this method to clear all subscriptions, for example, before removing the checkout or finishing work with the SDK.
  2. The method automatically removes all subscriptions created via checkout.events.subscribe.
General example of using subscriptions:
1// subscribe an event handler
2const readySubscription = CheckoutSDK.checkout.events.subscribe(
3  'ready',
4  (payload) => {
5    console.log('Checkout is ready:', payload);
6  }
7);
8
9// cancel handling of the 'ready' event
10readySubscription.unsubscribe();
11
12// remove all subscriptions for all events
13CheckoutSDKinstanse.checkout.events.unsubscribeAll();
Available events
Type
Description
Payload
ready

Triggered when the checkout content is fully loaded and ready for interaction.
Contains information about the selected payment method, autocharge status, and the URL applied in the iframe src attribute.

1{ 
2  paymentMethod: PaymentMethodName; 
3  autocharge: boolean; 
4  iframeUrl: string; 
5}
payButtonReady

Triggered when the third-party pay button (Apple Pay, Google Pay, or PayPal) is rendered and ready for the user to click.

1{ 
2  paymentMethod: 'apple_pay' | 'google_pay' | 'pay_pal'; 
3}
redirect

Triggered when the checkout requests a redirect to another URL.

redirectUrl – the URL to which the user should be redirected.

shouldOpenInNewTab – indicates whether the link should be opened in a new browser tab.

1{ 
2  redirectUrl: string; 
3  shouldOpenInNewTab: boolean; 
4}
changePaymentMethod

Triggered when the user changes the payment method in the checkout. Works only for checkouts that have tabs for switching payment methods.

1{ 
2  paymentMethod: PaymentMethodName; 
3}
submit

Triggered when the user clicks the Submit button that initiates the payment process, including payment methods like Apple Pay, Google Pay, and PayPal.
Also fires when checkout.submit is called.

1{ 
2  paymentMethod: PaymentMethodName; 
3  validationPassed: boolean;
4}
submitButtonLoading

Triggered when the submit button changes its loading state. This happens, for example, during card BIN validation.

1{ 
2  isLoading: boolean;
3}
paymentProcessingStart

Triggered at the start of payment processing.

1{ 
2  paymentMethod: PaymentMethodName; 
3}
paymentProcessingFinish

Triggered after payment processing is finished.
Contains information about the payment status at the end of processing.

1type PaymentProcessingFinishPayload  = 
2| { 
3  status: 'success'; 
4  paymentMethod: PaymentMethodName;
5  orderId: string;
6  email: string;
7}   
8| {
9  status: 'failed';
10  paymentMethod: PaymentMethodName;
11  reason?: string;
12}
error

Triggered when an unexpected error occurs during payment processing.

1{ 
2  error: string; 
3  paymentMethod: PaymentMethodName; 
4}
Useful type:
type PaymentMethodName: 'card' | 'google_pay' | 'apple_pay' | 'pay_pal' | 'spei' | 'sofort' | 'boleto' | 'ideal' | 'wechat' | 'alipay' | 'pix' | 'paytm' | 'paysafecard' | 'boleto_flash' | 'oxxo' | 'mercado_pago' | 'wire_transfer' | 'web_pay' | 'upi' | 'pay_with_crypto';
cleanup method

The cleanup method is used to finish SDK work. It clears all resources created during SDK usage, including removing the checkout, clearing event subscriptions, and unsubscribing from messages. This method ensures that the SDK does not leave any active subscriptions or resources after it finishes. Might be useful if user stays on the same page after the payment is completed.

What it does
  • Removes the checkout from the DOM.
  • Clears all subscriptions to checkout events.
Usage example
1// call the cleanup method to clear SDK resources
2CheckoutSDK.cleanup();
Notes
  1. After calling cleanup, the SDK instance can no longer be used. To use it again, you need to create a new instance via initCheckoutSDK.