Universal Checkout


The first fully dynamic checkout

Universal Checkout is a drop-in UI for web and mobile, with a no-code interface for product and payments teams. Now payments can be a first-class product area in your organization.

uc styling

🛒

Accessible and responsive UX that presents the payment methods you choose, along with 3D Secure 2.0 and convenient checkout modules, fully in-context with no redirects, ever!

🎛️

Use the Dashboard to activate a custom set of payment methods and checkout modules based on amount, currency, customer location and more.

🎨

Completely customizable, embedded UI for seamless user experience on your site or in your app

🔐

PCI Level 1 compliant with a centralized vault for recurring payments and one-click checkout

🎉

Low code integration that you won't have to touch when adding new payment methods, processors or other Connections

🚀

Fully dynamic checkout driven by Workflows that let you fully automate end-to-end payment flows for the first time

Payment method tokenization

Universal Checkout securely captures payment method data while fully embedded on your site or in your app. By communicating directly with Primer's PCI-L1 tokenization service, Universal Checkout transforms sensitive customer data into a secure uniform string called a payment method token.

You can safely pass this token to your backend to create payments with the Payments API, with no compliance risk.



payment instrument

🚀

Our agnostic tokenization service and centralized vault enable you to handle recurring payments, fallbacks and retries across processors without compromising UX. No more PSP-specific tokens — now you own your payments data.


So, how does it work?

flow

Whether you're embedding in a website or a mobile app:

  1. 1
    Generate a clientToken on your backend by creating a Client Session.
  2. 2
    Initialize Universal Checkout with the clientToken to render the UI.
  3. 3
    As the user interacts with the checkout, Universal Checkout will propose to update the Client Session using Client Session actions.
  4. 4
    Universal Checkout will generate a paymentMethodToken when the customer submits their payment data.
  5. 5
    Create a payment using the paymentMethodToken via the Payments API.
  6. 6
    If the response indicates a requiredAction , you'll get a new clientToken.
  7. 7
    Pass the clientToken back to Universal Checkout to render next steps, like 3DS, and get a resumeToken.
  8. 8
    Call POST/payments/{id}/resume with the resumeToken to wrap things up. (If a new requiredAction is returned, you'll have to go back to step 5.)
🚨

Universal Checkout can dynamically handle front-end payment flows constructed in Worklows such as 3D Secure, KYC and more, enabling your payments team to craft new commerce experiences with no additional code.


Manage your checkout with no code

The Dashboard features a no-code interface enabling you to simply drag-and-drop payment methods and checkout modules and create conditions that determine when and how they are displayed on Universal Checkout.

checkout builder


Generate a client token to initialize the SDK

The clientToken is a temporary key used to initialize Universal Checkout, and render the checkout options you've configured with the Dashboard.

Generate the first client token by creating a Client Session.

If a payment method or checkout module requires additional information passed in the Client Session this will be documented in the Connection setup in the Dashboard.

client token

Client session request POST/client-session

12345678910111213141516
curl --location --request \ POST 'https://api.sandbox.primer.io/client-session' \ --header 'X-Api-Key: <YOUR_API_KEY>' \ --header 'X-Api-Version: 2021-10-19' \ # These fields can be passed in the payment request as well --data '{    "orderId": "<YOUR_ORDER_ID>",    "currencyCode": "GBP",    "amount": 1200,    # a customerId is required to reuse sucessfully authorized payment method data for your customer    # we recommend you always pass this in if you intend to use vaulting    "customerId": "<YOUR_CUSTOMER_ID>"    "metadata": { }, }'
curl
copy

🚨

Data you pass when requesting a clientToken is persisted in the payment request unless explicitly overwritten.

Client token response

Check the warnings array for missing data which may be required to display certain payment methods and checkout modules in the Universal Checkout.

123456789101112
{  "clientToken": "<THE_CLIENT_TOKEN>",  "clientTokenExpirationDate": "2021-08-12T16:14:08.578695",  "orderId": "<YOUR_ORDER_ID>",  "currencyCode": "GBP",  "amount": 1200,  "customerId": "<YOUR_CUSTOMER_ID>",  "metadata": { },  "warnings": [    "Apple Pay is missing 'customerDetails.countryCode'"  ]}
JSON
copy

Implement Universal Checkout on front-end

Step 1. Install the Universal Checkout web SDK with npm

Install the Universal Checkout web SDK.

12345
# With yarnyarn add @primer-io/checkout-web# With npmnpm install --save @primer-io/checkout-web
bash
copy

Import the SDK and default CSS.

12345
// checkout.jsimport { loadPrimer } from '@primer-io/checkout-web'import '@primer-io/checkout-web/dist/Checkout.css` // Using a CSS loaderconst PrimerPromise = loadPrimer()
typescript
copy
🔓

If your checkout page uses the Content-Security-Policy header, you'll need to add a few things to your whitelist.

Step 2. Initialize Universal Checkout and render the UI

Create a client session and use the generate client token to initialize the Universal Checkout SDK. Call primer.checkout() to render the checkout in the specified container element.

12345678910111213141516171819202122232425
// checkout.jsimport { loadPrimer } from '@primer-io/checkout-web'import '@primer-io/checkout-web/dist/Checkout.css' // Using a CSS loaderconst PrimerPromise = loadPrimer()window.addEventListener('load', onLoaded)async function onLoaded() {    const Primer = await PrimerPromise    const primer = new Primer({        credentials: {            // Your server-generated client session token            clientToken: '<THE_CLIENT_TOKEN>',        },    })    const checkoutOptions = {        // The HTML element to render the checkout in        container: '#checkout-container',    }    // `.checkout()` initializes and renders the UI    await primer.checkout(checkoutOptions)}
typescript
copy
💡

Some payment methods and checkout modules will require you to pass in specific objects when creating a client session. Don't worry, nothing will break. Check console.log if you're seeing unexpected results.

Step 3. Handle callback for updating the client session

As the customer interacts with the UI, Universal Checkout fires "client session actions" via onClientsessionActions(). Forward these to your server to update the client session with the Client Session Actions endpoint.

A new client token will be provided. Pass it back to the

12345678910111213
const checkoutOptions = {    /* Other options and callbacks */    // Called during the checkout flow    // Universal Checkout may stay in loading state until this Promise is resolved or rejected    async onClientSessionActions(data) {        // Send the actions to your server to update the client session        const response = await updateClientSession(data.actions)        // Refresh the checkout with the latest data from the client session        return { clientToken: response.clientToken }    },}
typescript
copy

Step 4. Handle callbacks for creating and resuming payments

Once the payment method data has been securely captured, Primer will return a uniform paymentMethodToken via onTokenizeSuccess(). This can be safely passed to your server to create a payment with the Payments API.

Handling onTokenizeSucess():
  • When a customer submits their payment data, the payment details are tokenized and you'll receive a paymentMethodToken in onTokenizeSuccess()
  • Create a payment request with paymentMethod.token
  • If the payment is successful, return true in order to display a success screen.
  • If the payment is unsuccessful, throw an error to display an error / failed message.
  • Payments API may return a new clientToken for additional steps. In this case, return clientToken

1234567891011121314151617181920
const checkoutOptions = {    /* Other options and callbacks */    // Called after a payment method is tokenized    // Checkout stays in loading state until this Promise is resolved or rejected    async onTokenizeSuccess(paymentMethod) {        // Send the Payment Method Token to your server        // to create a payment using Payments API        const response = await createPayment(paymentMethod.token)        // If a new clientToken is available, resolve the Promise to refresh the client session.        // The checkout will automatically perform the action required by the Workflow.        if (response.requiredAction.clientToken) {            return { clientToken: response.requiredAction.clientToken }        }        // Display the success screen.        return true    },}
typescript
copy
Handle onResumeSuccess() callback:
  • You will receive a resumeToken via the onResumeSuccess() callback if applicable
  • Send a resume payment request with resumeToken
  • If the payment is successful, return true in order to display a success screen.
  • If the payment is unsuccessful, throw an error to display an error / failed message.
  • Payments API may return a new clientToken for additional steps. In this case, return clientToken

12345678910111213141516171819
const checkoutOptions = {    /* Other options and callbacks */    // Called after a extra steps are completed    // Checkout stays in loading state until this Promise is resolved or rejected    async onResumeSuccess(data) {        // Send the resume token to your server to resume the payment        const response = await resumePayment(data.resumeToken)        // If a new clientToken is available, resolve the Promise with it to refresh the client session        // The checkout will automatically perform the action required by the Workflow        if (response.requiredAction.clientToken) {            return { clientToken: response.requiredAction.clientToken }        }        // Display the success screen        return true    },}
typescript
copy
© Primer 2021