Android


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.

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 v2.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" }  }'
curl
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 the Universal Checkout

Step 1. 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.

Step 2. Prepare Universal Checkout's event listener

Prepare the UniversalCheckout.EventListener that will handle the events that happen during the lifecycle:

12345678910111213141516171819202122232425262728
class CheckoutActivity : AppCompatActivity() {   private val listener = object : CheckoutEventListener {     override fun onCheckoutEvent(e: CheckoutEvent) {      when (e) {        is CheckoutEvent.TokenizationSuccess -> {          /* TODO */        }        is CheckoutEvent.ResumeSuccess -> {          /* TODO */        }        else -> // handle other events      }    }  }   override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)     configureCheckout()  }   private fun configureCheckout() {    // with default settings    Primer.instance.configure(listener = listener)  }}
kotlin
copy

Step 3. Prepare the Client Token

Make an API call to your backend to fetch a Client Token. Here is a simple example of how it can be done:

12345678910111213141516171819202122232425262728
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)  }   // prepare the client (docs here)  private fun fetchClientToken() = viewModel.fetchClientToken()   private fun setupObservers() {    viewModel.clientToken.observe(this) { clientToken ->      // show checkout    }  }}
kotlin
copy
12345678910
class CheckoutViewModel : ViewModel() {     private val _clientToken= MutableLiveData<String>()    val clientToken: LiveData<String> = _clientToken     fun fetchClientToken() {    // fetch your token here (ask your backend to provide token) add our docs to exlain       _clientToken.postValue("retrieved_token")    }}
kotlin
copy

Step 4. Show Universal Checkout

When the client token is retrieved, show Universal Checkout.

1234567891011121314
class CheckoutActivity : AppCompatActivity() {   // other code goes here   private fun setupObservers() {    viewModel.clientToken.observe(this) { clientToken ->      showUniversalCheckout(clientToken)    }  }   private fun showUniversalCheckout(clientToken: String) {    Primer.instance.showUniversalCheckout(this, clientToken)  }}
kotlin
copy

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 CheckoutEvent.TokenizationSuccess that can be safely passed to your server to create a payment with the Payments API.

Handle CheckoutEvent.TokenizationSuccess event

1234567891011
private val listener = object : CheckoutEventListener {   override fun onCheckoutEvent(e: CheckoutEvent) {    when (e) {      is CheckoutEvent.TokenizationSuccess -> {        viewModel.sendPaymentMethodToken(e.data, e.resumeHandler)      }      //...    }  }}
kotlin
copy
12345678910111213141516171819
class CheckoutViewModel : ViewModel() {   //..  fun sendPaymentMethodToken(token: PaymentMethodToken, handler: ResumeHandler)  {    // Send the payment method token to your server to create a payment    // (https://primer.io/docs/payments/#one-create-a-payment-request) with `paymentMethod.token`    val paymentResponse =  //...    if (paymentResponse.isSuccessful()) {      // If the payment is successful, call resumeHandler.handleSuccess().      handler.handleSuccess()    } else if (paymentResponse.isPending()) {      // Payments API may return a new `clientToken` for additional steps. In this case, call `resumeHandler.handleNewClientToken(clientToken)`      handler.handleNewClientToken(paymentResponse.requiredAction.clientToken)    } else {      // If the payment is unsuccessful, call `resumeHandler.handleError(error: Error)` to show an error / failed message.      handler.handleError(Error())    }  }}
kotlin
copy

Handle CheckoutEvent.ResumeSuccess event

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

1234567891011
private val listener = object : CheckoutEventListener {   override fun onCheckoutEvent(e: CheckoutEvent) {    when (e) {      is CheckoutEvent.ResumeSuccess -> {        viewModel.sendResumeToken(e.resumeToken, e.resumeHandler)      }      //...    }  }}
kotlin
copy
123456789101112131415161718
class CheckoutViewModel : ViewModel() {   //...  fun sendResumeToken(token: String, handler: ResumeHandler)  {    // Send a resume payment request with resumeToken (https://primer.io/docs/payments/#two-handle-resuming-payment-flows)    val paymentResponse =  //..    if (paymentResponse.isSuccessful()) {      // If the payment is successful, call resumeHandler.handleSuccess().      handler.handleSuccess()    } else if (paymentResponse.isPending()) {      // Payments API may return a new `clientToken` for additional steps. In this case, call `resumeHandler.handleNewClientToken(clientToken)`      handler.handleNewClientToken(paymentResponse.requiredAction.clientToken)    } else {      // If the payment is unsuccessful, call `resumeHandler.handleError(error: Error)` to show an error / failed message.      handler.handleError(Error())    }  }}
kotlin
copy

Create a Payment

Once you've received a paymentMethodToken from Universal Checkout, use it to create a payment.

payment creation

Payment request POST/payments

1234567891011
curl --location --request \    POST 'https://api.sandbox.primer.io/payments' \    --header 'X-Api-Key: <YOUR_API_KEY>' \    --header 'X-Api-Version: 2021-09-27' \    --header 'X-Idempotency-Key: <YOUR_IDEMPOTENCY_KEY>' \    --data '{        "orderId": "<YOUR_ORDER_ID>",        "amount": 800,        "currencyCode": "GBP",        "paymentMethodToken": "<PAYMENT_METHOD_TOKEN>",    }'
curl
copy
Required fields
Description
  1. orderId
your unique order ID
  1. amount

payment amount
example in currency (USD) with minor units: 700 for \$7.00
example in currency (JPY) without minor units: 100 for ¥100

  1. currencyCode

ISO 4217 three-letter currency code: USD for US dollars

  1. paymentMethodToken

paymentMethodToken obtained from Universal Checkout or the Payment Methods API

Data passed in the payment request overwrites any data passed in the clientToken.

See more request options in the API Reference.


Payment response

The payment request is synchronous. It will trigger a Workflow and return a payment object containing, among other things, the payment status. In circumstances where the payment flow is asynchronous, you may receive a status of PENDING.

12345678910111213
// 2XX response {    "id": "slklmjh4",    "status": "AUTHORIZED",    "orderId": "<YOUR_ORDER_ID>",    "currencyCode": "GBP",    "amount": 800,    "paymentMethodToken": "<PAYMENT_METHOD_TOKEN>"     // ... additional attributes for the Payment object    // ... see API ref}
json
copy

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

To receive updates about the status of your payments you’ll need to listen to webhooks. Head to the Developers area to setup 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.