Headless Universal Checkout is currently in beta for iOS, Android and React Native. The following payment methods are unsupported:


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 Universal Checkout capture sensitive PCI card data or other form data.

As with all versions of Universal Checkout, any payment method can be added and configured through Dashboard, meaning Primer handles the logic of when to display each method.

Primer Headless Universal Checkout works in a simple way:

  1. 1
  2. Get a clientToken from your server
  3. 2
  4. Start Primer Headless Universal Checkout with the client token
  5. 3
  6. Primer Headless Universal Checkout will then return the available payment methods for the session initiated. Those payment methods that have been configured in the Dashboard and whose conditions match the current client session will be returned.
  7. 4
  8. Show the list of available payment methods.
  9. 5
  10. When the user selects a payment method, show its UI to enable the user to enter their credentials. Depending on the payment method, you will have to either ask the SDK to render it, or build the UI yourself.
  11. 6
  12. Primer Headless Universal Checkout will then create a payment for you and manage its lifecycle. You will receive a confirmation of payment with the checkout completed callback.

Headless Universal Checkout is currently available in beta on React Native. This documentation is only relevant for v2.1.0 and upward.

Headless Universal Checkout on React Native does not support card components at the moment.


Step 1. Prepare the Headless Universal Checkout callbacks

Set the Headless Universal Checkout callbacks to handle what happens during the checkout’s lifecycle.

const onAvailablePaymentMethodsLoad = (paymentMethodTypes: string[]) => {    // paymentMethodTypes contains the payment methods identifiers available    // for the client session.} const onPrepareStart = (paymentMethodType: string) => {    // Payment methods is getting prepared.} const onPaymentMethodShow = (paymentMethodType: string) => {    // Payment method did get presented.} const onTokenizeStart = (paymentMethodType: string) => {    // Started tokenization of payment method.} const onCheckoutComplete = (checkoutData: PrimerCheckoutData) => {    // It will receive the payment when it's done} const settings: PrimerSettings = {    // Any other settings & callbacks (see the Quick Start Guide    // and the SDK API reference)     onAvailablePaymentMethodsLoaded: onAvailablePaymentMethodsLoaded,    onPrepareStart: onPrepareStart,    onPaymentMethodShow: onPaymentMethodShow,    onTokenizeStart: onTokenizeStart,    onCheckoutComplete: onCheckoutComplete,}

Step 2. Start Headless Universal Checkout

Once you have a client token, you can initialize Primer’s Headless Checkout like below, and wait to receive the available payment method types for this client session:

try {    const paymentMethodTypes = await PrimerHeadlessUniversalCheckout.startWithClientToken(session.clientToken, settings)    setPaymentMethodTypes(paymentMethodTypes)     // Process payment methods} catch (e) {    // Handle error}

Once Primer’s Headless Checkout is configured, its callbacks will notify you about Headless Universal Checkout events.


Check the SDK API here to customize your SDK settings.

Step 3: Show available payment method

When the checkout is done initializing and you have received the available payment methods, you can show the list of payment methods to the user.

You can get the assets for each payment method using the function getAssetForPaymentMethodType.

// Get the logos of the payment methods available for this sessionconst paymentMethodsImageUrls = (    await Promise.all(        paymentMethodTypes.map(paymentMethodType =>            PrimerHeadlessUniversalCheckout.getAssetForPaymentMethodType(paymentMethodType, 'logo'),        ),    )).reduce((acc, logo, index) => {    acc[paymentMethodTypes[index]] = logo    return acc}, {}) // paymentMethodsImageUrls[paymentMethodType] contains the logo for the payment method

Assuming you have stored the logo URLs in paymentMethodsImageUrls, you can now render the available payment methods.

const renderPaymentMethods = () => {    return (        <View>            {paymentMethodTypes.map(paymentMethodType => {                return (                    <TouchableOpacity                        key={paymentMethodType}                        onPress={() => {                            payWithPaymentMethod(paymentMethodType)                        }}                    >                        <Image source={{ uri: paymentMethodsImageUrls[paymentMethodType] }} resizeMode='contain' />                    </TouchableOpacity>                )            })}        </View>    )}

Step 4: Handle payment method selection

When the user selects a payment method, you can present the relevant payment form.

const payWithPaymentMethod = (paymentMethodType: string) => {    try {        await PrimerHeadlessUniversalCheckout.showPaymentMethod(paymentMethodType)    } catch (err) {        // Handle the error    }}

The user can now interact with Universal Checkout, and the SDK will create the payment. The payment’s data will be returned on onCheckoutComplete configured in Step 1.

Did It Work?

If everything went well, you should be able to see the payment you just created on your Dashboard under the Payments menu. Payment list