Guides • Accept Payments
Android
doc

Accept payments via Revolut Pay - Android

Welcome to the implementation guide for Revolut Pay on Android! This page provides a comprehensive walkthrough for integrating Revolut Pay into your Android application.

Revolut Pay - Mobile

How it works

From an implementation perspective, integrating Revolut Pay into your Android app with the Revolut Pay SDK involves the following components:

  1. Server-side: An endpoint on your server to securely create an order with the Revolut Merchant API.
  2. Client-side: Your Android app uses the Revolut Pay SDK to display the Revolut Pay button, collect payment details, and handle the user flow.
  3. Endpoint for webhooks: Optionally, you can set up an endpoint to receive webhook events from the Merchant API to track the payment lifecycle. For more information, see: Use webhooks to keep track of the payment lifecycle.

The SDK automatically adapts the user experience based on whether the customer has the Revolut app installed, either by switching to the app or by presenting a secure in-app web flow, requiring no conditional logic in your implementation.

  1. The customer goes to the checkout screen in your app.
  2. The customer taps the Revolut Pay button.
  3. Your app uses your server endpoint to create an order and obtains the order token via the Merchant API: Create an order.
  4. The Revolut Pay SDK opens the Revolut app, where they review and authorise the payment.
  5. The SDK processes the payment and presents the payment result to the customer.
  6. Once the payment is successful, your customer is redirected to your app.
  7. Optionally, your server receives webhook notifications about each event you're subscribed to. For more information, see: Use webhooks to keep track of the payment lifecycle.
info

For more information about the order and payment lifecycle, see: Order and payment lifecycle.

Implementation overview

Check the following high-level procedure of implementing Revolut Pay in your Android app.

  1. Set up an endpoint for creating orders
  2. Configure your Android project
  3. Initialise the SDK
  4. Add the Revolut Pay button
  5. Handle the payment result

Before you begin

Before you start this tutorial, ensure you have completed the following steps:

Implement Revolut Pay on Android

1. Set up an endpoint for creating orders

Before the Revolut Pay button can be displayed in your app, your client-side code needs to fetch a unique, single-use token that represents an order. This token can only be created on your server by making a secure call to the Revolut Merchant API.

This server-side endpoint is a mandatory security requirement. Your secret API key must never be exposed in your Android application.

When a customer taps the Revolut Pay button in your app, your app will call this endpoint. Your endpoint is then responsible for:

  1. Receiving the checkout details (e.g., amount, currency) from your client-side request.
  2. Securely calling the Merchant API: Create an order endpoint with the checkout details.
  3. Receiving the order object, including the public token, in the API response.
  4. Returning the token from the response to your app.

Later, in the client-side configuration, the createOrder callback function will call this endpoint to fetch the token, which is required to initialise the SDK and display the Revolut Pay button.

Below is an example of the JSON response your endpoint will receive from the Merchant API after successfully creating an order. The crucial field to extract and return to your app is the token.

{
"id": "6516e61c-d279-a454-a837-bc52ce55ed49",
"token": "0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
"type": "payment",
"state": "pending",
"created_at": "2023-09-29T14:58:36.079398Z",
"updated_at": "2023-09-29T14:58:36.079398Z",
"amount": 1000,
"currency": "GBP",
"outstanding_amount": 1000,
"capture_mode": "automatic",
"checkout_url": "https://checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
"enforce_challenge": "automatic"
}

2. Configure your Android project

This section covers the one-time setup tasks required to prepare your Android project for the SDK.

2.1 Install the SDK

  1. Add the mavenCentral() repository to your project-level build.gradle file if it's not already there:

    allprojects {
    repositories {
    mavenCentral()
    }
    }
  2. Add the Revolut Pay SDK dependency to your module-level build.gradle file:

    implementation 'com.revolut:revolutpayments:1.0.0'
    implementation 'com.revolut:revolutpay:2.8'
  3. Sync your project with the Gradle files.

note

The minimum supported Android SDK version is API 21 (Android 5.0).

2.2 Configure the App Manifest

You need to declare necessary permissions and app-querying capabilities in your AndroidManifest.xml.

  1. Add internet permission: The SDK required network access.

    <uses-permission android:name="android.permission.INTERNET" />
  2. Declare Revolut app query: To allow the SDK to check if the Revolut app is installed, add the <queries> element.

    <queries>
    <package android:name="com.revolut.revolut" />
    </queries>

A deep link is required for the Revolut app to redirect the user back to your app after payment authorisation.

In your AndroidManifest.xml, add an <intent-filter> to the activity that will handle the result.

<activity
android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="payment-return"
android:scheme="myapp" />
</intent-filter>
</activity>
Important
  • Replace myapp and payment-return with a unique scheme and host for your app.
  • The activity launchMode must be singleTop to ensure the existing activity instance receives the result instead of creating a new one.

3. Initialise the SDK

In your application's entry point (e.g., the onCreate method of your Application class), initialise the Revolut Pay SDK with your public API key.

import com.revolut.revolutpayments.RevolutPayments
import com.revolut.revolutpay.api.revolutPay
import android.net.Uri

// ...

RevolutPayments.revolutPay.init(
environment = RevolutPayEnvironment.SANDBOX, // Or .MAIN
returnUri = Uri.parse("myapp://payment-return"), // Must match the deep link
merchantPublicKey = "<yourPublicApiKey>",
requestShipping = false, // Used for Fast checkout implementation
customer = null
)

This configures the SDK with the environment for testing or live payments and the deep link URI you configured in the previous step.

4. Implement the payment flow

Now, you will add the Revolut Pay button to your UI and connect it to your backend to handle payments.

4.1 Add the Revolut Pay button

You can add the Revolut Pay button to your checkout screen either programmatically or via XML layout.

Create an instance of the button in your activity or fragment code.

import com.revolut.revolutpayments.RevolutPayments
import com.revolut.revolutpay.api.revolutPay
import com.revolut.revolutpay.api.button.ButtonParams
import com.revolut.revolutpay.api.params.Radius
import com.revolut.revolutpay.api.params.Size
import com.revolut.revolutpay.api.params.Variant
import com.revolut.revolutpay.api.params.VariantModes
import com.revolut.revolutpay.api.params.BoxText

// ...

val buttonParams = ButtonParams(
size = Size.LARGE,
radius = Radius.Medium,
variantModes = VariantModes( lightMode = Variant.DARK, darkMode = Variant.LIGHT ),
boxText = BoxText.NONE
)

val revolutPayButton = RevolutPayments.revolutPay.provideButton(
context = this,
params = buttonParams
)

// Add the button to your view hierarchy
your_layout.addView(revolutPayButton)
info

For more information on available parameters or customising the button's appearance, see: Revolut Pay Android SDK and Revolut Pay button guidelines.

4.2 Start the payment on button tap

When the customer taps the button, you must fetch the token from your server and pass it to the SDK to start the payment flow.

Attach a controller to your button and implement the setHandler callback.

revolutPayButton.createController().apply {
setHandler { flow ->
// This block is executed on button tap.
// 1. Show a loading indicator in your UI.

// 2. Call your backend to create an order.
viewModel.createOrderOnBackend { orderToken ->
// 3. Provide the token to the SDK.
flow.setOrderToken(orderToken = orderToken)

// Optionally, you can configure MIT here, by setting the parameter to `true`
flow.setSavePaymentMethodForMerchant(savePaymentMethodForMerchant = false)

// 4. Allow the SDK to manage its state with the UI lifecycle.
flow.attachLifecycle(viewLifecycleOwner.lifecycle)

// 5. Start the payment confirmation flow.
flow.continueConfirmationFlow()
}
}
// ... attach the result callback in the next step
}

4.3 Handle payment result

The payment result is delivered back to your app in two parts: the deep link redirect and a callback for updating your UI.

  1. Handle the deep link redirect

    In the activity you configured with the <intent-filter>, override onNewIntent to pass the incoming URI to the SDK. The SDK processes this URI to determine the payment outcome.

    override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    intent?.data?.let { uri ->
    // Pass the deep link URI to the Revolut Pay SDK for processing
    RevolutPayments.revolutPay.handle(uri)
    }
    }
  2. Update the UI with the result

    The result processed from the deep link is delivered to the OrderResultCallback. Set this callback on your button controller to update your UI accordingly.

    revolutPayButton.createController().apply {
    setHandler { /* ... from previous step ... */ }

    setOrderResultCallback(object : OrderResultCallback {
    override fun onOrderCompleted() {
    // Payment successful.
    // Hide loading indicator and show a success message.
    }
    override fun onOrderFailed(throwable: Throwable) {
    // Payment failed.
    // Hide loading indicator and show an error message.
    }
    override fun onUserPaymentAbandoned() {
    // User cancelled the payment.
    // Hide loading indicator and return to checkout.
    }
    })
    }
note

The callbacks are executed on the main thread. For network operations like creating an order, ensure you switch to a background thread (e.g., using Kotlin Coroutines or RxJava).

5. Verify payments on your backend

caution

The client-side OrderResultCallback is for UI updates only. Its delivery is not guaranteed due to network conditions or other issues. You must rely on server-to-server webhooks to get the final, authoritative status of a payment before fulfilling the order.

Set up a webhook listener on your server to receive events like ORDER_COMPLETED and ORDER_PAYMENT_FAILED. Your order fulfillment logic should be triggered only after receiving a successful payment event via a webhook.

Advanced features

You can enable additional features for enhanced customer experience:

  • Fast checkout: To collect shipping details via Revolut Pay, pass requestShipping = true during SDK initialisation. This requires your backend to support the Fast checkout flow. See the Fast Checkout guide for details.
  • Merchant Initiated Transactions (MIT): To save a customer's payment method for future use (e.g., subscriptions), call the setSavePaymentMethodForMerchant(savePaymentMethodForMerchant: Boolean) function the createController method right after setting the order token. See our guide on charging a saved payment method for details.
  • Promotional banner: You can also add promotional banners to your checkout screen to boost your conversion. See the providePromotionalBannerWidget method for more details.
note

Fast checkout and MIT are mutually exclusive. You can enable one or the other, but not both in the same transaction.

Add a promotional banner

You can use the promotional banner widget to offer rewards to customers who create a new Revolut account after checkout.

Boost Your Conversions!

We recommend implementing the promotional banner. Analysis has shown that having the widget can increase conversion to payment by ~5%.

The banner is best placed on your order confirmation or "thank you" screen, which you display after the payment is successfully completed.

To add the banner, call the RevolutPayments.revolutPay.providePromotionalBannerWidget(context: Context, params: PromoBannerParams) method. This requires BannerParams, which includes the transactionId from your server.

// In your order confirmation Activity (e.g., OrderConfirmationActivity.kt)

import com.revolut.revolutpay.api.Currency
import com.revolut.revolutpay.api.params.Customer
import com.revolut.revolutpay.api.params.DateOfBirth
import com.revolut.revolutpay.api.params.PromoBannerParams
import com.revolut.revolutpay.api.revolutPay
import com.revolut.revolutpay.domain.model.CountryCode
import com.revolut.revolutpayments.RevolutPayments

class OrderConfirmationActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_order_confirmation)

// 1. Get the order token you passed to this activity after a successful payment.
// This is the `token` from the order object you received from your server in Step 1.
val orderIdFromServer = intent.getStringExtra("ORDER_ID") ?: ""

// 2. Define the parameters for the banner.
val bannerParams = PromoBannerParams(
transactionId = orderIdFromServer,
paymentAmount = 1000, // Amount in the smallest currency unit (e.g., cents)
currency = Currency.EUR,
customer = Customer(
name = "Example Customer",
email = "example.customer@email.com",
phone = "+441234567890",
dateOfBirth = DateOfBirth(_day = 1, _month = 2, _year = 2000),
country = CountryCode.GB,
)
)

// 3. Create the banner widget.
val promotionalBanner = RevolutPayments.revolutPay.providePromotionalBannerWidget(
context = this,
params = bannerParams
)

// 4. Add the banner to your layout.
// Assuming you have a LinearLayout with id 'banner_container' in your XML file.
val bannerContainer = findViewById<LinearLayout>(R.id.banner_container)
bannerContainer.addView(promotionalBanner)
}
}
Customising the banner's appearance (Optional)

To apply a custom theme to the banner, first define a style in a resource file:

<style name="RevolutPay_RevolutPayBanner">
<item name="revolutPay_ColorAccent">#0666EB</item>
<item name="revolutPay_ColorBackground">#F7F7F7</item>
<item name="revolutPay_BannerCornerRadius">12dp</item>
<item name="revolutPay_ComponentCornerRadius">12dp</item>
<item name="revolutPay_StrokeWidth">0dp</item>
<item name="revolutPay_StrokeColor">#BBC4CD</item>
</style>

Then, reference this theme when creating the widget:

val promotionalBanner = RevolutPayments.revolutPay.providePromotionalBannerWidget(
context = this,
params = bannerParams,
themeId = R.style.RevolutPay_RevolutPayBanner
)

Example

For a complete, working implementation, please refer to the example app included in our public SDK repository.

To run the example app:

  1. Clone the repository.
  2. Open the project in Android Studio, or your preferred IDE.
  3. Run the example app.

Implementation checklist

note

The Sandbox environment is designed to replicate the production environment's behaviour, with the key difference being the absence of app redirection due to the lack of a sandbox version of the Revolut retail app.

For more information about Revolut Pay payment flows in Sandbox, see: Test flows.

Before going live, use this checklist to test your integration in both the SANDBOX and MAIN (production) environments.

Project setup

  • mavenCentral() is in build.gradle.
  • SDK dependency is added.
  • AndroidManifest.xml: INTERNET permission is present.
  • AndroidManifest.xml: <queries> tag is present.
  • AndroidManifest.xml: Deep link <intent-filter> is configured with a unique scheme/host.
  • The deep link activity has launchMode="singleTop".
  • SDK is initialised with the correct public API key, environment, and returnUri.

Payment flow

  • The Revolut Pay button appears correctly on the checkout screen.
  • Tapping the button successfully calls your server to create an order and receives a token.
  • Test case 1 (Revolut app not installed): The payment flow completes successfully within the in-app web flow.
  • Test case 2 (Revolut app installed): The payment flow correctly redirects to the Revolut app and back.
  • A successful payment shows a success message in the UI via the onOrderCompleted callback.
  • A failed payment shows an appropriate error message in the UI via the onOrderFailed callback.
  • The user cancelling the payment flow is handled gracefully via the onUserPaymentAbandoned callback.

Backend verification

  • Webhook endpoint is created and subscribed to events.
  • Order fulfillment is triggered only by a ORDER_COMPLETED webhook.

What's next

Was this page helpful?