@primer-io/checkout-web
TypeScript icon, indicating that this package has built-in type declarations

2.28.0 • Public • Published

Primer Web SDK

Primer's Official Universal Checkout Web SDK




💪 Features of the Web SDK

💳   Create great payment experiences with our highly customizable Universal Checkout

🧩   Connect and configure any new payment method without a single line of code

  Dynamically handle 3DS 2.0 across processors and be SCA ready

♻️   Store payment methods for one-click checkout, recurring and repeat payments

📱   Proprietary Apple & Google Pay integrations that work with any PSP

🔒   Always PCI compliant without redirecting customers


📚 Documentation

Consider looking at the following resources:


💡 Support

For any support or integration related queries, feel free to Contact Us.


📋 Prerequisites

  • 🔑 Generate a client token by creating a client session in your backend
  • 🧱 Prepare a container in which to render Universal Checkout
  • 🎉 That's it!

🧱 Installation

With npm (recommended)

Our Web SDK is available on npm under the name @primer-io/checkout-web.

This package includes TypeScript definitions.

# With yarn
yarn add @primer-io/checkout-web

# With npm
npm install --save @primer-io/checkout-web

Then import Primer in your application

import { Primer } from '@primer-io/checkout-web';

// For example
Primer.showUniversalCheckout(clientToken, {
  /* Options */
});

With our CDN

Include the Primer.min.js script on the page where you want the checkout to be rendered.

Ensure that you're providing the desired version in the script tag. In the case below, it's v2.0.0:

<link rel="stylesheet" href="https://sdk.primer.io/web/v2.0.0/Checkout.css" />

<script
  src="https://sdk.primer.io/web/v2.0.0/Primer.min.js"
  crossorigin="anonymous"
></script>

Primer.min.js will add the Primer object to the global scope.

const { Primer } = window;

// For example
Primer.showUniversalCheckout(clientToken, {
  /* Options */
});

🎉 Ways of integrating the SDK

The simplest way to integrate with Primer is with our Drop-In Universal Checkout. With just a few lines of code, you can display a fully in-context checkout UI with all your payment methods.

Where there is a need for more customization and control over the checkout experience, a headless version of Primer’s Universal Checkout is available. You can use Headless Universal Checkout with your own UI, giving you more flexibility and allowing you to move faster when making design changes, while still having Primer capture sensitive PCI card data or other form data.


Drop-In Universal Checkout

🚀 Quick start

Take a look at our Quick Start Guide for accepting your first payment with Universal Checkout.

👩‍💻 Usage

🔍 Rendering the checkout

Availing Universal Checkout is as easy as implementing one line of code:

import { Primer } from '@primer-io/checkout-web';

const universalCheckout = await Primer.showUniversalCheckout(
  clientToken,
  options,
);

Below is an example of a basic implementation of Universal Checkout:

const clientToken = '...'; // client token retrieved from your backend

const options = {
  // Container element which will contain the checkout
  container: '#container',

  onCheckoutComplete({ payment }) {
    // Notifies you that a payment was created
    // Move on to next step in your checkout flow:
    // e.g. Show a success message, giving access to the service, fulfilling the order
  },
};

const universalCheckout = await Primer.showUniversalCheckout(
  clientToken,
  options,
);

Note that there are more options which can be passed to Universal Checkout. Please refer to the section below for more information.

Wait for Universal Checkout to be loaded

Primer.showUniversalCheckout(clientToken, options) returns a Promise that is resolved when Universal Checkout has been properly rendered on the page.

// With await
try {
  const universalCheckout = await Primer.showUniversalCheckout(
    clientToken,
    options,
  );
  console.log('Universal Checkout is ready!');
} catch (e) {
  console.log('Failed to show Universal Checkout', e);
}

// With then/catch
Primer.showUniversalCheckout(clientToken, options)
  .then((universalCheckout) => {
    console.log('Universal Checkout is ready!');
  })
  .catch((e) => {
    console.log('Failed to show Universal Checkout', e);
  });

🧰 Checkout Options

When calling showUniversalCheckout you can provide Universal Checkout with some configuration options.

These options range from callbacks notifying you of the current payment's status, to styling options for certain UI elements.

Below are some options to consider when integrating Universal Checkout:

🚀 General Options

⚙️ Container and locale

option Type Description
container string or Element The container element in which the checkout should be rendered required
locale string This option forces the locale. By default, the locale will be set to the browser's locale optional

⚙️ Payment Lifecycle Callbacks

Callbacks can be provided to Universal Checkout which will notify you on certain checkout events such as payment creation.

These callbacks can be used to inform you on the current state of the checkout.

We strongly recommend you to implement onCheckoutComplete to redirect the user to an order confirmation page when the payment is successful:

const options = {
  /* Other checkout options ... */

  onPaymentCreationStart() {
    // Notifies you before the checkout tokenizes a payment method
    // and creates a payment
  }

  onBeforePaymentCreate(data, handler) {
    // Notifies you that a payment will be created
    // Update your UI accordingly
    // e.g. Show custom loading UI, etc.
    // Abort or continue with payment creation
    // Primer will continue with payment creation if onBeforePaymentCreate is not implemented

    // ⚠️ You MUST call one of the functions of the `handler` if `onBeforePaymentCreate` is implemented

    // Choose to abort a payment
    return handler.abortPaymentCreation();

    // Choose to continue with payment creation
    return handler.continuePaymentCreation();
  },

  onCheckoutComplete({ payment }) {
    // Notifies you that a payment was created
    // Move on to next step in your checkout flow:
    // e.g. Show a success message, giving access to the service, fulfilling the order, ...
  },

  onCheckoutFail(error, { payment }, handler) {
    // Notifies you that the checkout flow has failed and a payment could not be created
    // This callback can also be used to display an error state within your own UI.

    // ⚠️ `handler` is undefined if the SDK does not expect anything from you
    if (!handler) {
      return;
    }

    // ⚠️ If `handler` exists, you MUST call one of the functions of the handler

    // Show a default error message
    return handler.showErrorMessage();

    // Show a custom error message
    return handler.showErrorMessage('This is my custom error message');
  },
};

⚙️ Client Session Lifecycle Callbacks

Callbacks can be provided to Universal Checkout which will notify you on client session update events.

const options = {
  /* Other checkout options ... */

  onBeforeClientSessionUpdate() {
    // Notifies you that the client session is in the process of being updated
    // Use it to show a loading indicator on your UI
  },

  onClientSessionUpdate(clientSession) {
    // Notifies you when the client session has been updated by the checkout
    // Returns updated client session
    // Updated client session can be used to inform your UI
    // e.g. update tax, shipping or discount amounts displayed to your customers
  },
};

⚙️ Payment Method Callbacks

To receive updates on which payment method was selected by a customer, you can use the following callback:

const options = {
  /* Other checkout options ... */

  onPaymentMethodAction(action, { paymentMethodType }) {
    // Notifies you when a specific payment method has been selected or unselected
    // action will either be 'PAYMENT_METHOD_SELECTED' or 'PAYMENT_METHOD_UNSELECTED'
  },
};

💳 Payment Methods Options

Learn more about the payment method specific options.


🎨 Customization Options

Learn more about the customization options.

⚙️ Styling

option Type Description Default
style Object Custom style applied to the UI.
Learn more about the capabilities in our Customization Guide
Default style optional

⚙️ Form Options

option Type Description Default
form.inputLabelsVisible Boolean Choose whether to show the label above inputs true optional

⚙️ Submit Button Options & Callbacks

Universal Checkout allows you to use your own submit button for submitting forms. By default, the built-in submit button will be favored:

option Type Description Default
submitButton.useBuiltInButton Boolean Set whether to use built-in submit button or to display your own custom button true optional
submitButton.amountVisible Boolean Set whether the total order amount should be displayed in the submit button content false optional

Note that when disabling the built-in submit button and using your own custom submit button, it is required to implement the submit() function in order to notify Universal Checkout of form submissions.
Read more about the submit() function in the Manual Form Submission section referenced below.


When using your own custom submit button, it's important to use the following callbacks to ensure that your submit button is in the correct state and in sync with the checkout as your customers interact with it:

const options = {
  /* Other options ... */

  submitButton: {
    useBuiltInButton: false, // Default to true

    // Callback for receiving the submit button's visible state in the current scene
    onVisible(isVisible, context: { currentSceneId }) {
      // Show or hide your custom submit button
    },

    // Callback for receiving the submit button's disabled state in the current scene
    onDisable(isDisabled, context: { currentSceneId }) {
      // Disable or enable your custom submit button
    },

    // Callback for receiving the submit button's loading state in the current scene
    onLoading(isLoading, context: { currentSceneId }) {
      // Show your submit button in a loading state
    },

    // Callback for receiving the submit button's content in the current scene
    onContentChange(content, context: { currentSceneId }) {
      // Set your submit button's content with either the content provided or your own custom content
    },
  },
};

⚙️ Processing Indicator Options

Show a processing indicator overlay on top of the checkout when submitting a form:

option Type Description Default
processingIndicator.visible Boolean Choose whether a processing indicator overlay should be shown on form submission true optional

⚙️ Error Message Options & Callbacks

When Universal Checkout encounters errors processing payments, these errors will be shown to your users by default, below the submit button.

If you want to show your own error messages, you have the option to disable the default, built-in error messages:

option Type Description Default
errorMessage.disabled Boolean Choose whether to allow Universal Checkout to show error messages false optional

You can use the following callbacks to get notified when Universal Checkout intends to display an error message. By using these callbacks, you can respond with your own UI changes and avail a custom error message:

const options = {
  /* Other options ... */

  errorMessage: {
    disabled: false, // Default to false

    // A callback for when the error message should be displayed
    onErrorMessageShow(message) {
      // Choose to use provided message for own purposes
    },

    // A callback for when the error message should be hidden
    onErrorMessageHide() {
      // Update own UI accordingly
    },
  },
};

⚙️ Success Screen Options

When the checkout is succefully complete, Universal Checkout displays a success scene with a default success message "Your payment was successful!".

Set the option successScreen to modify the behavior of the success scene.

const options = {
  /* Other options ... */

  // Remove the success screen
  successScreen: false,

  // Change the message of the default success screen
  successScreen: {
    type: 'CHECK',
    title: 'This is a custom success message!',
  },
};

🔨 Advanced Options

⚙️ Manual Payment Creation & Tokenization Lifecycle Callbacks

By default, Universal Checkout will automatically create payments and manage their lifecycles on your behalf. The manual payment creation flow used in previous Web SDK versions is still supported.

Check our Manual Payment Creation guide.

⚙️ Show the flow for a single payment method

The payment methods featuring a dedicated screen allows you to directly display their flow. For that, make sure to:

  • Set uxFlow to SINGLE_PAYMENT_METHOD_CHECKOUT
  • Set paymentMethod to the payment method you want to display
const options = {
  /* Other options ... */

  uxFlow: 'SINGLE_PAYMENT_METHOD_CHECKOUT',
  paymentMethod: 'PAYMENT_CARD',
};

Payment methods that supports this flow

  • Card: PAYMENT_CARD
  • Klarna: KLARNA
  • GoCardless: GOCARDLESS

⚙️ Customizable Payment Method Button options

Some payment methods enables you to customize the payment method button.

option Type Description Default
logoSrc String Data URL representing the logo you want to display in the payment method button. required
background String Color of the background of the payment method button. required
logoAlt String Accessibility marker for the payment method button required
text String Label to display to the right of logoSrc Only show logoSrc optional

Payment methods that supports this flow

  • Gift Cards with Mollie: PAYMENT_CARD

🔧 Checkout Methods

Universal Checkout exposes some methods which can be called to perform some specific actions:

Updating the Client Session

When updating the client session, after the checkout has been initialized, you will receive a client token in the response returned from PATCH /client-session.

In order for the checkout to know that you have updated the client session, you will need to pass this new client token back to the checkout:

const universalCheckout = await Primer.showUniversalCheckout(
  clientToken,
  options,
);

// Refresh client session by calling refreshClientSession
// This will result in Universal Checkout having access to the latest changes made to the client session
universalCheckout.refreshClientSession();

Note that refreshClientSession replaces the deprecated setClientToken method since version v2.11.0.

Manual Form Submission

The checkout provides a method for manually calling submit. This is useful when using your own custom submit button.

const universalCheckout = await Primer.showUniversalCheckout(
  clientToken,
  options,
);

const handleMySubmitButtonClick = () => {
  // Forward all submit button clicks to the SDK
  universalCheckout.submit();
};

Disabling Tokenization and Payment Creation

The checkout provides setPaymentCreationEnabled and setTokenizationEnabled to enable or disable tokenization and payment creation. Use this if you would like to prevent users from paying because your side of the checkout is not valid.

These two functions can be used interchangibly.

const universalCheckout = await Primer.showUniversalCheckout(
  clientToken,
  options,
);

// Disable payment creation
universalCheckout.setPaymentCreationEnabled(false);
universalCheckout.setTokenizationEnabled(false);

// Enable payment creation
universalCheckout.setPaymentCreationEnabled(true);
universalCheckout.setTokenizationEnabled(true);

Headless Universal Checkout

👩‍💻 Usage

🔍 Initialize the headless checkout

Once you have a client token, you can initialize Primer’s Headless Checkout with Primer.createHeadless(clientToken).

You should then configure the onAvailablePaymentMethodsLoad listener. The listener will return the available payment methods for the client session.

Payment methods are added and configured through Primer's Dashboard. The listener will return the payment methods whose conditions match the current client session.

Below is an example of a basic implementation of Headless Universal Checkout:

const clientToken = '...'; // client token retrieved from your backend

async function onAvailablePaymentMethodsLoad(paymentMethods) {
  for (const paymentMethod of paymentMethods) {
    switch (paymentMethod.type) {
      case 'PAYMENT_CARD': {
        // Configure your card form
        // await configureCardForm();
        break;
      }
      case 'PAYPAL': {
        // Render the payment method button
        // configurePayPalButton();
        break;
      }
      case 'APPLE_PAY': {
        // Render the payment method button
        // configureApplePayButton();
        break;
      }
      case 'GOOGLE_PAY': {
        // Render the payment method button
        // configureGooglePayButton();
        break;
      }
      // More payment methods to follow
    }
  }
}

function onCheckoutComplete({ payment }) {
  console.log('onCheckoutComplete', payment);
}

function onCheckoutFail(error, { payment }, handler) {
  console.error('onCheckoutFail', error, payment);

  handler?.showErrorMessage('fail');
}

const { Primer } = window;

const headless = await Primer.createHeadless(clientToken);

await headless.configure({
  onAvailablePaymentMethodsLoad,
  onCheckoutComplete,
  onCheckoutFail,
});

await headless.start();

console.log('Headless Universal Checkout is loaded!');

Note that there are more options which can be passed to Universal Checkout. Please refer to the section below for more information.

🧰 onAvailablePaymentMethodsLoad

onAvailablePaymentMethodsLoad return a list of objects, each representing a payment method. This what each object is made of:

option Type Description
type string The payment method type. e.g. PAYMENT_CARD, PAYPAL, ADYEN_IDEAL, ... required
managerType CARD, NATIVE, REDIRECT The type of manager to instantiate with createPaymentMethodManager required

🚀 Create your UI

Primer enables you to create the UI that suits your needs, using the provided inputs and components we provide.

Handle payment methods

Handling payment methods is done by instantiating a payment method manager using createPaymentMethodManager(paymentMethodType: string, options). The instance of the manager depends on managerType.

Handle card forms

When the payment method's managerType is CARD (relevant for the payment method type PAYMENT_CARD), use the payment method manager to build your own card form using Primer input elements.

See the relevant (documentation)[https://primer.io/docs/accept-payments/headless-universal-checkout/web/#show-card-components] for further instructions.

Handle native payment method buttons

When the payment method's managerType is NATIVE, use the payment method manager to render the payment method button to your customers.

See the relevant (documentation)[https://primer.io/docs/accept-payments/headless-universal-checkout/web/#render-the-button] for further instructions

Handle redirect payment methods

When the payment method's managerType is REDIRECT, use the payment method manager to start the redirect flow.

See the relevant (documentation)[https://primer.io/docs/accept-payments/headless-universal-checkout/web#step-4c-handle-payment-methods-with-redirect] for further instructions.

🧰 Headless Options

option Type Description
paymentHandling string Either AUTO (default) or MANUAL optional
locale string This option forces the locale. By default, the locale will be set to the browser's locale optional

🧰 Headless Methods

When you call primer.createHeadless(clientToken), you get an instance of PrimerHeadlessCheckout:

export interface PrimerHeadlessCheckout {
  // Set the configuration of the headless checkout
  configure: (options: HeadlessUniversalCheckoutOptions) => void;
  // Start the headless checkout
  start: () => void;
  // Create a payment method manager
  createPaymentMethodManager;
}

createPaymentMethodManager

createPaymentMethodManager creates a manager based on the provided payment method type.

And the following managers (with their methods):

CardPaymentMethodManager

Method Parameters Output Description
createHostedInputs - {cardNumberInput: HeadlessHostedInput, expiryInput: HeadlessHostedInput, cvvInput: HeadlessHostedInput} Creates instances of the hosted inputs.
createHostedInput name: CreditCardFieldName HeadlessHostedInput Creates a hosted input based on the type.
removeHostedInputs - - Removes all of the hosted input fields from the DOM.
setCardholderName cardholderName: string - Set the cardholder name.
validate - Promise<Validation> Validates all the hosted inputs.
submit - - Submits all the data from the hosted inputs, tokenizes the card data and creates the payment.
reset - - Resets all the inputs.

NativePaymentMethodManager

Method Parameters Output Description
createButton - HeadlessPaymentMethodButton Creates the button for the payment method

RedirectPaymentMethodManager

Method Parameters Output Description
start - Promise<void> Starts the redirect flow, shows a popup, and handle the web view.

getAssetsManager

Use the AssetsManager to get access to assets for each of the available payment methods.

const assetsManager = headless.getAssetsManager();

const assets: ButtonPaymentMethodAsset = await assetsManager.getPaymentMethodAsset(
  'MOLLIE_IDEAL',
);

ButtonPaymentMethodAsset

Field Type Description
iconUrl object Object containing colored, darkand light: each being URL to download the icon of the payment method.
paymentMethodName string Human-readable payment method name.
backgroundColor string Object containing colored, darkand light: each being background color we encourage you to use for the payment method button.

Values

Below are some types mentioned above:

Type Values
CreditCardFieldName cardNumber, expiryDate, cvv

Classes

Below are some classes mentioned above (and their methods):

HeadlessHostedInput

Method Parameters Output Description
getName - string Get the name of the hosted input
getOptions - HeadlessHostedInputOptions Get all the available optons for the hosted input.
setOptions options: HeadlessHostedInputOptions - Set options on the hosted input.
addEventListener event: EventTypes, callback: EventListener - Add an event listener.
render container: string, options: HeadlessHostedInputOptions - Render the hosted input in a container.
focus - - Focus the hosted input UI.
blur - - Blur the hosted input UI.
setDisabled status: boolean - Disable the hosted input UI.

HeadlessPaymentMethodButton

Method Parameters Output Description
render containerId: string, options: HeadlessButtonRenderOptions - Render the button in your container.
setDisabled disabled: boolean - Disable or enable the button.
clean - - Hide the button.
blur - - Unfocus the button.
focus - - Focus the button.
addEventListener event: EventTypes, callback: EventListener - Add an event listener.

HeadlessHostedInputOptions

Field Type Description
placeholder string Placeholder text.
ariaLabel string Label
style Record<string, any> All the style to apply.

HeadlessButtonRenderOptions

Field Type Description
style GooglePayStyles | PayPalStyles | ApplePayStyles All the style to apply.

Validation

Field Type Description
valid boolean Whether the value is valid or not.
validationErrors [InputValidationError] A list of validation errors.
error string The raw error.

InputValidationError

Field Type Description
name string A friendly name for the validation error.
error string The raw error.
message string The error message.

InputMetadata

Field Type Description
errorCode string An error code in the case of an error.
error string The raw error.
valid boolean Is the input data valid.
active boolean Is the input active.
dirty boolean Is the input dirty.
touched boolean Is the input touched.
submitted boolean Has the input been submitted

Payment

Field Type Description
id string The payment ID. Used to look up the payment on the Primer API.
orderId string Your provided order ID.
paymentMethodData PaymentMethodData Additional payment method data.

PrimerClientError

Field Type Description
code ErrorCode A unique error identifier.
message string The raw error message.
diagnosticsId string A unique ID to give to Primer for support.

Style options

PayPalStyles

Field Type
buttonColor 'gold' | 'blue' | 'silver' | 'white' | 'black'
buttonShape 'pill' | 'rect'
buttonSize 'small' | 'medium' | 'large' | 'responsive'
buttonHeight number
buttonLabel 'checkout' | 'credit' | 'pay' | 'buynow' | 'paypal' | 'installment'
buttonTagline boolean

GooglePayStyles

Field Type
buttonColor 'default' | 'black' | 'white'
buttonType 'long' | 'short'

ApplePayStyles

Field Type
buttonColor 'default' | 'black' | 'white'
buttonType 'plain' | 'buy' | 'set-up' | 'donate' | 'check-out' | 'book' | 'subscribe'
buttonStyle 'white' | 'white-outline' | 'black'

🧰 Headless Events

Hosted Input Events

On a hosted input, you can listen to an event as follows:

cardNumberInput.addEventListener('change', (...args) => {
  console.log('cardNumberInput change', ...args);
});

And the following event types are supported:

enum EventTypes {
  CHANGE = 'change',
  ERROR = 'error',
  FOCUS = 'focus',
  BLUR = 'blur',
}

Callbacks

You can register various callbacks on the headless checkout using configure as follows:

...
// Create an instance of the headless checkout
const headless = await Primer.createHeadless(clientToken);

// Configure headless
await headless.configure({
    onAvailablePaymentMethodsLoad,
    onCheckoutComplete,
    onCheckoutFail
});

The following callbacks are required:

Callback Parameters Description
onAvailablePaymentMethodsLoad paymentMethods: PaymentMethodData[] Get the list of payment methods you should handle.

The following callbacks are optional:

Callback Parameters Description
onBeforePaymentCreate {payment: Payment}, handler Triggered before the payment is created.
onCheckoutComplete {payment: Payment} Triggered on a successful payment.
onCheckoutFail error: PrimerClientError, {payment: Payment}, handler Triggered if the payment fails for any reason.

Keywords

none

Install

npm i @primer-io/checkout-web

DownloadsWeekly Downloads

6,822

Version

2.28.0

License

MIT

Unpacked Size

145 kB

Total Files

6

Last publish

Collaborators

  • stickycube
  • aladin.taleb
  • primer-developers