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:

FieldDescription
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:

123456789101112131415161718192021222324252627282930313233343536
curl --location --request \ POST 'https://api.sandbox.primer.io/client-session' \ --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",    }}
bash
copy

To use new Workflows and all of its exciting features, make sure to pass the following header in your API request:

1
Legacy-Workflows: false
shell
copy

See this migration guide for more information.

Install the SDK

Add the following to your app/build.gradle file:

1234567
repositories {  mavenCentral()}
dependencies {  implementation 'io.primer:android:latest.version'}
kotlin
copy

For more details about SDK versions, please see our changelog.

It is highly recommended adding the following settings to your app/build.gradle file:

12345
android {    kotlinOptions {        freeCompilerArgs += '-Xjvm-default=all'    }}
kotlin
copy

Initialize Universal Checkout

Prepare the PrimerCheckoutListener that will handle the callbacks that happen during the lifecycle. Import the Primer SDK and set its listener as shown in the following example:

1234567891011121314151617181920212223
class CheckoutActivity : AppCompatActivity() {
  private val listener = object : PrimerCheckoutListener {
    // 👇 [Required] This function is called when the checkout has been completed    override fun onCheckoutCompleted(checkoutData: PrimerCheckoutData) {      // Show an order confirmation screen, fulfil the order...      // checkoutData contains the payment that has been created    }  }
  override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_main)
    configureCheckout()  }
  private fun configureCheckout() {    // 👇 Initialize the SDK with the default settings.    Primer.instance.configure(settings = PrimerSettings(), listener = listener)  }}
kotlin
copy
🛠

See all the configurations in the SDK Reference.

Show Universal Checkout

At this step you should have a client token available - see Manage Client Sessions for more.

When the client token is retrieved, show Universal Checkout by calling showUniversalCheckout method:

123456789101112131415161718192021222324252627282930
class CheckoutActivity : AppCompatActivity() {
  // other code goes here  private lateinit var viewModel: CheckoutViewModel
  override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_main)
    setupViewModel()    setupObservers()    fetchClientToken()  }
  private fun setupViewModel() {    viewModel = ViewModelProvider(this).get(CheckoutViewModel::class.java)  }
  private fun fetchClientToken() = viewModel.fetchClientToken()
  private fun setupObservers() {    viewModel.clientToken.observe(this) { clientToken ->        showUniversalCheckout(clientToken)     } }
 private fun showUniversalCheckout(clientToken: String) {    Primer.instance.showUniversalCheckout(this, clientToken) }}
kotlin
copy

You should now be able to see Universal Checkout! The user can now interact with Universal Checkout, and the SDK will create the payment. The payment’s data will be returned on onCheckoutCompleted() configured in the previous step.

When the user interacts with the checkout and clicks to pay, the Universal Checkout:

  • Shows the payment method screen if applicable
  • Tokenizes the payment method for payment
  • Creates the payment
  • Handles any other interactions (e.g. 3DS)

Handle successful payments

Listen to callback

Listen to onCheckoutCompleted callback

This function will notify you of a successful payment

1234567
private val listener = object : PrimerCheckoutListener {
  override fun onCheckoutCompleted(checkoutData: PrimerCheckoutData) {    // Show an order confirmation screen, fulfil the order...    // checkoutData contains the payment that has been created  }}
kotlin
copy

Handle webhooks in your dashboard

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 https://webhook.site to test your implementation.

Handle failed payments

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

1234567891011121314151617
private val listener = object : PrimerCheckoutListener {
  override fun onFailed(    error: PrimerError,    checkoutData: PrimerCheckoutData?,    errorHandler: PrimerErrorDecisionHandler?  ) {    // 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.
    // Show a default error message    errorHandler?.showErrorMessage(null)
    // Show a custom error message    errorHandler?.showErrorMessage("This is my custom error message")  }}
kotlin
copy