Overview

With version 2 of our Web SDK, Universal Checkout automatically creates and handles Payments by default. This greatly reduces the complexity and amount of boilerplate required to integrate Primer.

For backward compatibility reasons, it is still possible to manually create and resume payments. Follow this guide to setup Universal Checkout so that you handle the payment lifecycle.

Flow

flow

  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
    Universal Checkout will generate a paymentMethodToken when the customer submits their payment data, or when they select particular payment methods.
  4. 4
    Create a payment using the paymentMethodToken via the Payments API POST/payments
  5. 5
    If the response indicates a requiredAction, you'll get a new clientToken.
  6. 6
    Pass the clientToken back to Universal Checkout to render next steps, like 3DS, and get a resumeToken.
  7. 7
    Call POST/payments/{id}/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.)

Generate a Client Token

Get an API Key

You require an API Key to talk with our APIs. Head to the Developers area to manage your API keys.

When your account is created, we will also create an API token automatically. You can use this API key to get started.

Only client_tokens:write is required as the scope of the key.

Never share your API Key, only your backend should have access to it.

Find out more about API Keys in our API Reference

Generate a Client Session

Client token

A client session is the starting point for integrating payments at Primer. You can attach all the metadata associated with the order to the client session, and generate a clientToken, a temporary key used to initialize Universal Checkout.

The information you include in the client session is used in the Dashboard to conditionally route payments with Workflows, and activate payment methods and other features in Universal Checkout, so pass as much information as you can.

The X-Api-Version specifies the API version information. Earlier, this was supposed to be a date. For example, 2021-10-19.

This has changed post API version v2 which was represented by 2021-09-27 date.

Starting API version v2.1, the X-Api-Version needs to provide the API version as 2.1.

Depending upon the API version specified in the client-session request, your client-session will be processed accordingly with requisite features and options that are available for that version.

See API Reference Changelog for details.

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

POST/client-session
12345678910111213
# Generate a client token with cURLcurl --location --request \  POST 'https://api.sandbox.primer.io/client-session' \  --header 'X-Api-Key: <YOUR_API_KEY>' \  --header 'X-Api-Version: 2021-10-19' \  --header 'Content-Type: application/json' \  --data '{    "orderId": "<YOUR_ORDER_ID>",    "currencyCode": "GBP",    "amount": 1200,    "customerId": "<YOUR_CUSTOMER_ID>",    "order": { "countryCode": "GB" }  }'
bash
copy

Example Response

12345678910
{  "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": []}
JSON
copy
ℹ️
Make sure to pass all the information required by the payment methods and features activated on your Dashboard.

As a rule of thumb, pass as much information as you can when creating the client session. As a minimum, make sure to pass:

  • orderId
  • currencyCode
  • amount
  • order.countryCode

The clientToken is a key concept within Primer. You may receive a client token from various places but as long as you pass it to the SDK, Universal Checkout knows where to start/resume the flow.

Set up Universal Checkout

Step 1. Install

Add the following to your app/build.gradle file

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

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

Step 2. Initialize the SDK

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.

In order to use manual payment handling, you have to set paymentHandling to **PrimerPaymentHandling.MANUAL** in the PrimerSettings.

1234567891011121314151617181920212223242526272829303132333435
public class CheckoutActivity extends AppCompatActivity {
    private final PrimerCheckoutListener listener = new PrimerCheckoutListener() {
        @Override        public void onTokenizeSuccess(@NonNull PrimerPaymentMethodToken primerPaymentMethodToken,                                      @NonNull PrimerResumeDecisionHandler decisionHandler) {              // use the received paymentMethodToken to make the payment              // and use decisionHandler to instruct SDK about next steps based on payment status        }
        @Override        public void onResumeSuccess(@NonNull String resumeToken,                             @NonNull PrimerResumeDecisionHandler decisionHandler) {             // use the received resumeToken to resume the payment             // and use decisionHandler to instruct SDK about next steps based on payment status        }    };
    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);
        configureCheckout();    }
    private void configureCheckout() {        // Set the paymentHandling to manual        PrimerSettings settings = new PrimerSettings();        settings.setPaymentHandling(PrimerPaymentHandling.MANUAL);
        Primer.getInstance().configure(settings, listener);    }}
java
copy
🚀

Check the SDK API here to customize your SDK settings.

Step 3. Generate a client token

💡

For more information on generating a client token, take a look at our client session guide.

Make an API call to your backend to fetch a client token. Here is a simple example of how it can be done from your activity:

1234567891011121314151617181920212223242526272829
public class CheckoutActivity extends AppCompatActivity {
private CheckoutViewModel viewModel;
@Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);
        configureCheckout();        setupViewModel();        setupObservers();        fetchClientToken();    }
    private void setupViewModel() {        viewModel = new ViewModelProvider(this).get(CheckoutViewModel.class);    }
    private void fetchClientToken() {        viewModel.fetchClientToken();    }
    private void setupObservers() {        viewModel.clientToken.observe(this, clientToken -> {
        });    }}
java
copy

Your view model code may look something like this:

12345678910
public class CheckoutViewModel extends ViewModel {
    private final MutableLiveData<String> _clientToken = new MutableLiveData<>();    public LiveData<String> clientToken = _clientToken;
    public void fetchClientToken() {        // fetch your token here (ask your backend to provide token)        _clientToken.postValue("retrieved_token");    }}
java
copy

Step 4. Show Universal Checkout

When the client token is retrieved, show Universal Checkout.

123456789101112
public class CheckoutActivity extends AppCompatActivity {
    // other code goes here
    private void setupObservers() {          viewModel.clientToken.observe(this, this::showUniversalCheckout);    }
    private void showUniversalCheckout(String clientToken) {          Primer.getInstance().showUniversalCheckout(this, clientToken);    }}
java
copy
🔥

You should now be able to see Universal Checkout! The user can now interact with Universal Checkout.

Step 5. Handle callbacks for creating and resuming payments

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

Handle onTokenizeSuccess callback

  • 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 the payment method token data.

  • If the payment is successful, call decisionHandler.handleSuccess() in order to display a success screen.

  • If the payment is unsuccessful, call decisionHandler.handleFailure("Your error message") to display an error / failed message.

  • Payments API may return a requiredAction with a new clientToken for additional steps. In this case, call decisionHandler.continueWithNewClientToken(clientToken).

12345678910
private final PrimerCheckoutListener listener = new PrimerCheckoutListener() {
    @Override        public void onTokenizeSuccess(@NonNull PrimerPaymentMethodToken primerPaymentMethodToken,                                      @NonNull PrimerResumeDecisionHandler decisionHandler) {
            viewModel.sendPaymentMethodToken(primerPaymentMethodToken)            // ⚠️ remember to call decisionHandler to resume SDK flow.        }    };
java
copy

Handle onResumeSuccess callback

Once the required actions are completed, Primer will return resumeToken via onResumeSuccess that can be safely passed to your server to resume a payment with the Payments API.

  • You will receive a resumeToken via the onResumeSuccess() callback if applicable.

  • Send a resume payment request with resumeToken

  • If the payment is successful, call decisionHandler.handleSuccess() in order to display a success screen.

  • If the payment is unsuccessful, call decisionHandler.handleFailure("Your error message") to display an error / failed message.

  • Payments API may return a requiredAction with a new clientToken for additional steps. In this case, call decisionHandler.continueWithNewClientToken(clientToken).

123456789
private final PrimerCheckoutListener listener = new PrimerCheckoutListener() {
    @Override        public void onResumeSuccess(@NonNull String resumeToken,                             @NonNull PrimerResumeDecisionHandler primerResumeDecisionHandler) {            viewModel.sendResumeToken(resumeToken)            // ⚠️ remember to call decisionHandler to resume SDK flow.        }    };
java
copy