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

If you're looking for a more customizable way of integrating Universal Checkout, consider integrating Headless Checkout.

Not all payment methods are currently compatible with Drop-in Checkout.

Please refer to this table to learn more about the payment methods available for Drop-in Checkout.

Before you start

Before you start, make sure:

Create a client session

A client session is the starting point for integrating payments at Primer. You can attach any data associated with the order to your client session.

Creating a client session provides you with a client token, a temporary key used to initialize the Universal Checkout.

The information you include in the client session is used in the Dashboard:

  • to conditionally route payments with Workflows
  • to activate payment methods and other features in Universal Checkout

So pass as much information as you can!

Generate an API key

Requests to our API are authenticated using an API key in the X-Api-Key header. Create an API key by visiting the developer page of the Primer Dashboard.

Make sure to set the following scopes for your API Key:

  • client_tokens:write
  • transactions:authorize

Make a client session request

On your server, create a client session with POST/client-session.

Make sure to pass at least the following data:

Your reference for the payment.

Make sure to keep track of orderId - you will later receive updates to the payment via Webhooks. The payment will contain the orderId specified in the client session.
The three-letter currency code in ISO 4217 format.
e.g. use USD for US dollars.
  1. order
The details of the line items of the order.

The body of a successful response contains a clientToken that you will use to initialize the Universal Checkout.

Here is how the client session request to the Primer API should look like:

curl --location --request \ POST '' \ --header 'X-Api-Key: <YOUR_API_KEY>' \ --header 'X-Api-Version: 2.2' \ --header 'Content-Type: application/json' \ --data '{    "orderId": "<YOUR_ORDER_ID>",    "currencyCode": "GBP",    "amount": 5000,    "order": {      "lineItems": [{        "itemId": "shoes-123",        "amount": 2500,        "quantity": 2      }],      "countryCode": "GB"    } }'
# Here is a (heavily truncated) example response
{  "clientToken": "THE_CHECKOUT_SESSION_TOKEN",  "clientExpirationDate": "2022-03-08T14:00:00Z",  "orderId": "<YOUR_ORDER_ID>",  "currencyCode": "GBP",  "amount": 5000,    "order": {      "lineItems": [{        "itemId": "shoes-123",        "amount": 2500,        "quantity": 2      }],      "countryCode": "GB",    }}

Install the SDK

With npm

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

This package includes TypeScript definitions.

# With yarnyarn add @primer-io/checkout-web
# With npmnpm install --save @primer-io/checkout-web
import { Primer } from '@primer-io/checkout-web'
Primer.showUniversalCheckout(clientToken, {    /* Options */})
  • The npm package only works if used alongside a bundler such as Webpack or Parcel. If you're directly writing JavaScript using script tag, please use our CDN instead.
  • As of today, the npm package does not work in a server environment. If you are using Next.js, Gatsby, or a similar framework, make sure the Primer functions are called on the client side, or use our CDN instead.

With our CDN

Include the Primer.min.js script and the Checkout.css stylesheet on the page where you want to render the Checkout. Make sure to pass the proper version in the URL.

<link rel="stylesheet" href="" /><script src="" crossorigin="anonymous"></script>

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

const { Primer } = window
Primer.showUniversalCheckout(clientToken, {    /* Options */})

Initialize and Show Universal Checkout

Use the generated client token on the client-side to show Universal Checkout by calling Primer.showUniversalCheckout(clientToken, options). Make sure to pass a selector to your container in the options.

const universalCheckout = await Primer.showUniversalCheckout(clientToken, {    // Specify the selector of the container element    container: '#checkout-container',
    /**     * When the checkout flow has been completed, you'll receive     * the successful payment via `onCheckoutComplete`.     * Implement this callback to redirect the user to an order confirmation page and fulfill the order.     */    onCheckoutComplete({ payment }) {        console.log('Checkout Complete!', payment)    },
    /**     * When the checkout flow has been fail, you'll receive     * the error via `onCheckoutFail`     */    onCheckoutFail(error, { payment }, handler) {        console.log('Checkout Fail!', error, payment)    },})

When the user interacts with the checkout:

  • Update the client session
  • Create a payment (by default)

Handle successful payments

Listen to callback

On the client-side, listen to the onCheckoutComplete callback to be notified when the payment has been successfully completed. Use it to show an order confirmation screen, or to fulfill the order.

Handle webhooks

To receive updates about the status of your payments you’ll need to listen to webhooks. This is particularly useful for updating an order or any other data stored server-side.

Head to the Developers section of the Primer Dashboard to setup and test a webhook for PAYMENT.STATUS event.

If you are not yet ready to receive webhooks, you can use to test your implementation.

Handle redirects

Some payment methods require redirecting to another web page in order to capture payment details.

Drop-in checkout automatically renders that web page in a popup window in order to maintain the current context.

If the browser cannot open popup windows, the current window will be redirected instead.

To ensure maximum compatibility, read the guide on how to handle redirects.

Handle failed payments

Any errors, cancelled payment interactions or failed payments will trigger the onCheckoutFail callback

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');}