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?


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

  1. 1
    Generate a clientToken on your backend by creating a Client Session with POST/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. Forward them to your backend to update your Client Session with POST/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 POST/payments
  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/{paymentId}/resume with the resumeToken to resume the payment and 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 Workflows 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 with POST/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

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 successfully 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": { }, }'


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.

{  "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'"  ]}

Implement Universal Checkout on front-end

Step 1. Install the SDK

With CocoaPods

The iOS SDK is available with Cocoapods. Just add the PrimerSDK pod and run pod install.

target 'MyApp' do  # Other pods...   # Add this to your Podfile  pod 'PrimerSDK' # Add this lineend

For specific versions of the SDK, please refer to the changelog.

With Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into Xcode. Go to File > Swift Packages > Add Package Dependency. In the window that opens, enter https://github.com/primer-io/primer-sdk-ios.git

Step 2. Initialize the SDK

First import the SDK library in a Swift file containing theย UIViewController that will host Universal Checkout and its delegate.

import PrimerSDK class MyViewController: UIViewController {     override func viewDidLoad() {        super.viewDidLoad()         // Initialize the SDK with the default settings.        Primer.shared.delegate = self    }} extension MyViewController: PrimerDelegate {    // ...}

Step 3. Add the client token callback

When showing Universal Checkout, the SDK first asks you to retrieve a client session token by callingย clientTokenCallbackย on the delegate. Create your client session as described here.

In the meantime, a loading indicator is displayed.

extension MyViewController: PrimerDelegate {     func clientTokenCallback(_ completion: @escaping (String?, Error?) -> Void) {        // Request a client session token from your backend        requestClientSession(completion: { (clientToken, err) in            completion(clientToken, err)        })    }}

Step 4. Show Universal Checkout

When ready, display Universal Checkout.

class MyViewController: UIViewController {     func startUniversalCheckout() {        Primer.shared.showUniversalCheckout(on: self)    } }

Step 5. Handle callbacks for creating and resuming payments

Handle onTokenizeSuccess callback

When a customer submits payment data, the credentials are tokenized and you'll receive a payment method token inย onTokenizeSuccess(_:resumeHandler:)

Send the payment method token to your server to create a payment with the Payments API. The checkout stays in a loading state in the meantime.

Call the resumeHandler's handle(error:) to show an error message, or handleSuccess() to show a success message.

In case you receive a requiredAction with a new clientToken, call the resumeHandler's handle(newClientToken:) function.

Handle onResumeSuccess callback

The SDK will continue and you'll get notified of the resume result in one of the following delegate functions: onResumeSuccess(_:resumeHandler:) or onResumeError(_:).

If the onResumeSuccess(_:resumeHandler:) is called, use the resumeToken to resume your payment.

extension MyViewController: PrimerDelegate {     func onTokenizeSuccess(_ paymentMethodToken: PaymentMethodToken, resumeHandler: ResumeHandlerProtocol) {        createPayment(with: paymentMethodToken) { (res, err) in            if let err = err {                resumeHandler.handle(error: err)            } else if let res = res {                guard let requiredAction = res["requiredAction"] as? [String: Any],                    let clientToken = requiredAction["clientToken"] as? String                else {                    resumeHandler.handleSuccess()                    return                }                 resumeHandler.handle(newClientToken: clientToken)            }        }    }     func onResumeSuccess(_ resumeToken: String, resumeHandler: ResumeHandlerProtocol) {        // Resume the payment with the resumeToken.        resumePayment(with: resumeToken) { (res, err) in              if let err = err {                  resumeHandler.handle(error: err)              } else if let res = res {                  resumeHandler.handleSuccess()              }        }    }     func onResumeError(_ error: Error) {        // Handle the error    }}

Step 6: Handle callback for updating the client session

As the customer interacts with the UI, Universal Checkout fires "client session actions" via onClientSessionActions(:resumeHandler:). 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 SDK using the resumeHandler's handle(newClientToken:) to refresh Universal Checkout and continue the flow.

extension MyViewController: PrimerDelegate {     func onClientSessionActions(_ actions: [ClientSession.Action], resumeHandler: ResumeHandlerProtocol?) {        // Send the client session actions to your backend and update        // your client session.        requestClientSessionWithActions(actions) { (clientToken, err) in            if let err = err {                resumeHandler?.handle(error: err)            } else if let clientToken = clientToken {                resumeHandler?.handle(newClientToken: clientToken)            }        }    } }
// ClientSession.Actionvar type: Stringvar params: [String: Any]?