Migrating to Paystack UI - Android

In this guide, we'll show you how to migrate to Paystack UI, a collection of UI components and methods that allow you accept payment in your Android app.

What's new

Paystack UI was built from the ground-up in order to address the pain points of the former SDK:

  1. Extensibility: Previously, our SDK only supported card as a payment channel. We built the new SDK with a modular architecture that allows us add our available payment channels.
  2. Better UX: The SDK provides UI components with a cleaner look and intuitive experience for users when making payment.
  3. Security: Transactions are now initiated from the backend and completed on the mobile app, giving full control to the developer.
  4. Improved DX: We expose intuitive APIs that allow you to write fewer lines to code to achieve faster results

Integration flow

The former SDK required a good amount of effort to get the up and running. The developer needed to:

  • Initialize the SDK
  • Build an interface to collect the card details
  • Accept payment
  • Handle the different processing states
  • Handle callback

These steps, while seemingly easy, tend to require a lot of engineering effort with implementation and maintenance. With the Paystack UI, we took up the interface design and managing the processing states, giving developers the ability to focus on building their products. With Paystack UI, the developer would:

  • Initialize the SDK
  • Accept payment
  • Handle callback

Developers are simply interacting with ready-made interfaces as opposed to crafting theirs.

Updating dependencies

The first step to using the Paystack UI is adding it to your list of dependencies:

1dependencies {
2 // remove this
3 implementation 'co.paystack.android:paystack:3.1.2'
4 // add this
5 implementation 'com.paystack.android:paystack-ui:0.0.8'
Sync project

Don’t forget to sync project in order to pull in the library into your project.

With the dependency successfully installed, you can now import the library into your project:

1import com.paystack.android.core.Paystack
2import com.paystack.android.ui.paymentsheet.PaymentSheet

Updating the interfaces

The SDK needs to be initialized to be used, so this is the first code change we’ll be making:


Paystack UI

2 .setPublicKey("pk_your-public-key")
3 .build()

Unlike the former SDK, Paystack UI makes use of the builder pattern for the construction of object.


Callbacks are used to manage post-payment processes on the SDK side. This is how you manage the final state of the transaction.

1PaystackSdk.chargeCard(this, charge, object : TransactionCallback {
2 override fun onSuccess(transaction: Transaction) {
3 Log.d("Main Activity", "onSuccess: " + transaction.getReference);
4 }
6 override fun beforeValidate(transaction: Transaction) {
7 Log.d("Main Activity", "beforeValidate: " + transaction.reference)
8 }
10 override fun onError(error: Throwable, transaction: Transaction) {
11 Log.d("Main Activity", "onError: " + error.localizedMessage)
12 Log.d("Main Activity", "onError: $error")
13 }

Paystack UI

1private fun paymentComplete(paymentSheetResult: PaymentSheetResult) {
2 val message = when (paymentSheetResult) {
3 PaymentSheetResult.Cancelled -> "Cancelled"
4 is PaymentSheetResult.Failed -> {
5 Log.e("Something went wrong", paymentSheetResult.error.message.orEmpty(), paymentSheetResult.error)
6 paymentSheetResult.error.message ?: "Failed"
7 }
9 is PaymentSheetResult.Completed -> {
10 // Returns the transaction reference PaymentCompletionDetails(reference={TransactionRef})
11 Log.d("Payment successful", paymentSheetResult.paymentCompletionDetails.toString())
12 "Successful"
13 }
14 }

We've replaced the TransactionCallback with the PaymentSheetResult which exposes three states: Failed, Cancelled and Completed that can be used to manage post-payment processes.

Accept payment

Sample backend code

We have a sample backend app that you can reference as you build your backend.

Previously, accepting payment requires you to create an instance of a Card and Charge object. With Paystack UI, you initialize the transaction from your server using the Initialize TransactionAPI endpoint and use the access_code returned to trigger a PaymentSheet as shown below:

1val cardNumber = "4084084084084081"
2val expiryMonth = "11"
3val expiryYear = "24"
4val cvv = "408"
6val card = Card(cardNumber, expiryMonth, expiryYear, cvv)
8val charge = Charge()
9charge.card = card

Paystack UI

1private lateinit var paymentSheet: PaymentSheet
3override fun onCreate(savedInstanceState: Bundle?) {
4 super.onCreate(savedInstanceState)
5 // other code snippet
7 paymentSheet = PaymentSheet(this, ::paymentComplete)
10private fun makePayment() {
11 // Pass access_code from transaction initialize call
12 paymentSheet.launch("access_code")

You can now test your integration to confirm that everything is working fine.


Finally, you can remove the card activity or fragment and any other code that complements the UI you previously created. You can check out the reference page for more information on the methods and UI components available on Paystack UI.