Direct Google Pay™ integration for Android

This guide will help you integrate with Revolut APIs directly to accept Google Pay payments in your Android application. This guide assumes that you have already integrated the Google Pay API on your Android app and are ready to process payments through Revolut as your payment processor.

Google Pay Terms

Before integrating, review and accept the Google Pay Acceptable Use Policy and Terms of Service.

How it works

From an implementation perspective, integrating Google Pay with Revolut involves the following components:

  1. Server-side: You need to set up endpoints on your server that create orders and process payments using the Revolut Merchant API.
  2. Client-side: Your Android app uses the Google Pay API to collect encrypted payment tokens and communicates with your server.
  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 order and payment flow is as follows:

  1. Checkout and order creation: The customer navigates to checkout. Your app creates an order via the Revolut Merchant API, obtains the order token, and initialises the Google Pay button with Revolut-specific gateway parameters.
  2. Google Pay authorisation: The customer taps the Google Pay button and authorises the payment. Google Pay returns an encrypted payment token to your app.
  3. Payment processing: Your app sends the encrypted Google Pay token to create a payment request via the Revolut Merchant API. Your app then polls the payment status until a final state or challenge is returned.
  4. 3D Secure challenge (if required): If 3DS authentication is required, your app displays the challenge to the customer, who completes the authentication.
  5. Payment result: Your app shows the payment result to the customer.
  6. Webhooks: Your server receives webhook notifications about payment events.
Info

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

Implementation overview

Check the following high-level overview on how to implement direct Google Pay integration in your Android app:

  1. Configure redirect URL
  2. Create an order
  3. Initialise Google Pay with Revolut gateway parameters
  4. Create a payment request
  5. Handle payment results and track status

Before you begin

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

Implement Direct Google Pay integration

1. Configure redirect URL

Revolut only accepts HTTPS values in the 3ds_redirect_uri parameter. After a 3D Secure (3DS) challenge, the issuer's ACS redirects the customer to this URL. To return the customer to your Android app instead of leaving them in the browser, you must register the HTTPS URL as an Android App Link and verify your domain.

  1. Choose a HTTPS URL you control.
    Example: https://pay.example.com/3ds-return. You will pass this exact URL as 3ds_redirect_uri when creating the order in the next step.

  2. Add an App Link intent filter in your manifest for the activity that should receive the 3DS return:

    AndroidManifest.xml
    <activity
    android:name=".ThreeDsReturnActivity"
    android:exported="true">
    <intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
    android:scheme="https"
    android:host="pay.example.com"
    android:pathPrefix="/3ds-return" />
    </intent-filter>
    </activity>
  3. Host the Digital Asset Links file to verify that the HTTPS domain belongs to your app:

    https://pay.example.com/.well-known/assetlinks.json
    [
    {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
    "namespace": "android_app",
    "package_name": "com.example.app",
    "sha256_cert_fingerprints": [
    "12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF"
    ]
    }
    }
    ]

Use the SHA-256 fingerprint from the certificate you use to sign your release build. You can obtain it from your signing configuration (for example, via ./gradlew signingReport or the Play Console if you use Play App Signing).

Note

If you do not want to use an HTTPS redirect back into your app, omit 3ds_redirect_uri and handle the 3DS challenge in a WebView as described in Step 5.

2. Create an order

Create an order from your backend forwarding the data collected during checkout, and including your Secret API key in the authorisation header. We recommend creating the order when the customer is at your checkout, and you are ready to take the payment.

Send a POST request to the Create an order endpoint with the order details:

Request example
{
"amount": 100,
"currency": "GBP",
"3ds_redirect_uri": "https://pay.example.com/3ds-return",
"customer": {
"email": "customer@example.com"
}
}
ParameterDescriptionRequired
amountThe order amount in the smallest currency unit (e.g., cents). For £1.00, use 100.Yes
currencyThe three-letter ISO 4217 currency code (e.g., GBP, USD, EUR).Yes
capture_modeDetermines when funds are captured. Use automatic for immediate capture or manual for delayed capture.No
3ds_redirect_uriThe HTTPS URL where the customer will be redirected after completing the 3D Secure challenge (e.g., https://pay.example.com/3ds-return). Use the App Link you configured in Step 1. If not provided, you must handle the 3DS challenge in a WebView within your app.No
customerCustomer details for saving payment methods. Required if you want to save the payment method for future use. Include email for new customers or id for existing customers.No
Info

For complete details on all available parameters, see: Merchant API: Create an order.

Once the order is created successfully, the Merchant API returns a JSON object. Extract the token from the response as you will need it in the next step:

Response example
{
"id": "64d38f09-d04e-a9b5-b394-991f8a527eb3",
"token": "1112e405-c0b1-4a3f-a50d-e8acd66c7a8e",
"type": "payment",
"state": "pending",
"created_at": "2023-08-09T13:05:13.697830Z",
"updated_at": "2023-08-09T13:05:13.697830Z",
"capture_mode": "automatic",
"amount": 100,
"currency": "GBP",
"outstanding_amount": 100,
"checkout_url": "https://checkout.revolut.com/payment-link/999515ab-be9e-4477-b879-85b85c1576c1",
}

3. Initialise Google Pay with Revolut gateway parameters

Now you need to initialise the Google Pay button in your Android app so that your customer can initiate the payment. To initialise the button, follow the official Google guide to implement Google Pay on Android.

Brand guidelines

When integrating Google Pay, follow the Google Pay Android brand guidelines. Use the official button and logo assets as provided, without altering their colours, size, or appearance.

Payment configuration parameters

When requesting a payment token from Google for your payment provider, you need to set two specific values so that the payment token is encrypted specifically for Revolut as your payment processor.

Here's how to configure these parameters in your Android app, following the Google Pay tutorial:

Configure the tokenisation specification

First, configure how the payment token should be encrypted for Revolut:

GooglePayConfig.kt
import org.json.JSONArray
import org.json.JSONObject

// Order `token` obtained by creating an order in the Merchant API
val orderToken: String = createOrder().token

// Configure the tokenisation specification for Revolut
private fun getTokenizationSpecification(orderToken: String): JSONObject {
return JSONObject().apply {
put("type", "PAYMENT_GATEWAY")
put("parameters", JSONObject(mapOf(
"gateway" to "revolut",
"gatewayMerchantId" to orderToken // Order token from Step 2
)))
}
}
ParameterDescription
createOrder()Function in your app that calls your backend to create an order (Step 2) and returns the token from the response.
gatewaySet to "revolut" to identify Revolut as your payment processor.
gatewayMerchantIdSet to the orderToken variable, which contains the order token you received from Step 2: Create an order. This value must be dynamically obtained for each payment to maintain security.
Define card parameters

Next, specify which card networks and authentication methods you want to support:

GooglePayConfig.kt
// ... getTokenizationSpecification() from previous step

// Configure card parameters with allowed networks and authentication methods
private fun getCardParameters(): JSONObject {
return JSONObject(mapOf(
"allowedCardNetworks" to JSONArray(listOf(
"VISA",
"MASTERCARD",
"AMEX"
)),
"allowedAuthMethods" to JSONArray(listOf("PAN_ONLY", "CRYPTOGRAM_3DS"))
))
}
ParameterDescriptionSupported options
allowedCardNetworksCard networks that you want to accept for Google Pay payments. Choose the networks you want to support in your implementation.VISA, MASTERCARD, AMEX
allowedAuthMethodsAuthentication methods for card credentials.PAN_ONLY (physical card details), CRYPTOGRAM_3DS (tokenised virtual card) (subject to confirmation with Revolut)
Info

For complete details on the allowedCardNetworks parameter and card network configuration, refer to Google Pay Android API CardParameters

Supported card networks:

Revolut supports the following card networks for Google Pay processing:

  • VISA
  • MASTERCARD
  • AMEX (American Express)
Note

Card network support may vary depending on your merchant settlement country and agreement with Revolut. Consult with your Integration Specialist or Account Manager to confirm which card networks are enabled for your merchant account.

Supported authentication methods:

Google Pay provides two different authentication methods for card credentials. Revolut's integration supports both types, and merchants should enable the methods they need in their Google Pay configuration by setting the allowedAuthMethods parameter.

Description3DSProcessing
PAN_ONLYPhysical card details stored in Google PayRequired, standard 3DS flow appliesWhen you submit a payment with PAN_ONLY credentials, Revolut automatically handles the 3DS authentication. If the issuing bank requires authentication, you will receive a 3DS challenge response as described in Step 5: Handle the payment response.
CRYPTOGRAM_3DSTokenised virtual card stored on deviceNot required, authentication is performed by Google PayThese tokens are pre-authenticated by Google Pay and typically do not require additional 3DS authentication, as Google Pay has already performed strong customer authentication.
Info

When configuring your Google Pay implementation, specify both authentication methods in the allowedAuthMethods array as shown in the code example above. Revolut automatically processes the appropriate authentication flow based on the token type received from Google Pay.

Configure billing address collection

To process Google Pay payments, configure Google Pay to collect the customer's billing address (billingAddressRequired: true) in "FULL" format. The example below shows the recommended settings.

GooglePayConfig.kt
// Configure card parameters with billing address collection
private fun getCardParameters(): JSONObject {
return JSONObject(mapOf(
"allowedCardNetworks" to JSONArray(listOf(
"VISA",
"MASTERCARD",
"AMEX"
)),
"allowedAuthMethods" to JSONArray(listOf("PAN_ONLY", "CRYPTOGRAM_3DS")),
// Add billing address parameters
"billingAddressRequired" to true,
"billingAddressParameters" to JSONObject(mapOf(
"phoneNumberRequired" to false,
"format" to "FULL"
))
))
}
ParameterDescription
billingAddressRequiredWhether to collect billing address from the customer. Set to true.
billingAddressParameters.phoneNumberRequiredWhether phone number is required as part of the billing address. Set to false.
billingAddressParameters.formatLevel of detail to collect for the billing address. Set to "FULL".
Combine card parameters with tokenisation specification

Now extend your card configuration with the tokenisation specification:

GooglePayConfig.kt
// ... getTokenizationSpecification() and getCardParameters() from previous steps

// Combine parameters with tokenisation specification
private fun getCardPaymentMethod(orderToken: String): JSONObject {
return JSONObject().apply {
put("type", "CARD")
put("parameters", getCardParameters())
put("tokenizationSpecification", getTokenizationSpecification(orderToken))
}
}
Build the complete allowed payment methods configuration

Finally, create the complete payment methods array:

GooglePayConfig.kt
// ... previous functions from steps

// Build the complete allowed payment methods configuration
private fun getAllowedPaymentMethods(orderToken: String): JSONArray {
return JSONArray().put(getCardPaymentMethod(orderToken))
}

Next steps

Follow the rest of the Google guide to initiate the payment process with Google Pay.

The result of all these steps should be an encrypted payload (Payment token) that is ready to be used for payment processing.

4. Create payment request

In this step, your backend submits the Google Pay token and required metadata to Revolut to initiate the payment.

Initiate payment and receive PaymentData

Use the Google Pay PaymentsClient to call loadPaymentData() with the PaymentDataRequest you build from your Google Pay configuration. This is the point where the Google Pay UI is shown and the user authorises the payment. In the official Google guide, this is covered in Initiate a payment.

Use the Activity Result API with GetPaymentDataResult to receive the PaymentData response and handle success, cancellation, or errors. Once you have the PaymentData, continue with the extraction step below to retrieve the encrypted token and send it to your backend.

// Build the request from your Google Pay configuration
val paymentDataRequest = createPaymentDataRequest()

// Start the Google Pay flow and attach the result to the launcher
val paymentDataTask = paymentsClient.loadPaymentData(paymentDataRequest)
paymentDataTask.addOnCompleteListener(paymentDataLauncher::launch)

Extract payment details from PaymentData

From the PaymentData response, extract:

  • Payment token from paymentMethodData.tokenizationData.token
  • Billing address from paymentMethodData.info.billingAddress
  • Cardholder name from the billing address name

Here's how to extract this data in your Android app:

private val paymentDataLauncher = registerForActivityResult(GetPaymentDataResult()) { taskResult ->
when (taskResult.status.statusCode) {
CommonStatusCodes.SUCCESS -> {
taskResult.result?.let { paymentData ->
val paymentInfo = paymentData.toJson()
val paymentMethodData = JSONObject(paymentInfo)
.getJSONObject("paymentMethodData")

// Extract the encrypted token
val tokenizationData = paymentMethodData
.getJSONObject("tokenizationData")
val encryptedToken = tokenizationData.getString("token")

// Extract billing address
val billingAddress = paymentMethodData
.getJSONObject("info")
.optJSONObject("billingAddress")

// Extract the name for `cardholder_name` (if provided by Google Pay)
val cardholderName = billingAddress?.optString("name")

// Send the token + billing details to your backend. Your backend should map Google Pay
// `billingAddress` to the Revolut `billing_address` structure and pass `cardholder_name`.
sendPaymentToBackend(encryptedToken, billingAddress, cardholderName)
}
}
CommonStatusCodes.CANCELED -> Unit // Handle the user cancelling the payment
CommonStatusCodes.DEVELOPER_ERROR -> Unit // Handle errors the API returns (it.status: Status)
else -> Unit // Handle internal and other unexpected errors
}
}
Info

For complete details on the PaymentData response structure, see Google's PaymentData documentation.

Send these values to your backend server.

Send payment details to Revolut

Besides the encrypted token, Revolut expects billing_address and cardholder_name in the payment request, so your backend must extract them from the Google Pay PaymentData response:

  • Map the Google Pay billingAddress to the Revolut billing_address structure
  • Extract the billingAddress.name and send it as cardholder_name

Send a POST request to the Pay for an order endpoint:

Request example
{
"payment_method": {
"type": "google_pay",
"token": "{GOOGLE_PAY_TOKEN}", // Extracted from Google Pay `PaymentData`
"cardholder_name": "John Doe", // Extracted from Google Pay `PaymentData` billing address `name`
"billing_address": {
"street_line_1": "Example Street 123",
"street_line_2": "II/123",
"region": "London",
"city": "London",
"country_code": "GB",
"postcode": "123456"
},
"environment": {
"type": "browser",
"time_zone_utc_offset": 180,
"color_depth": 48,
"screen_width": 1920,
"screen_height": 1080,
"java_enabled": false,
"challenge_window_width": 640,
"browser_url": "https://www.mystore.com/webview/",
"client_ip": "74.23.11.101",
"user_agent": "Chrome 13.3",
"accept_header": "application/text",
"locale": "en-PH"
}
}
}

Payment request object:

ParameterDescriptionFormatRequired
payment_methodPayment method details for Google Pay.ObjectYes

Payment method object:

ParameterDescriptionFormatRequired
typeThe type of the payment method. Must be google_pay.StringYes
tokenUTF-8 encoded, serialised JSON object containing the encrypted payment token returned by Google Pay. See Google's documentation for the expected token structure.String (JSON)Yes
cardholder_nameCardholder name. Extract the name value from the Google Pay PaymentData billing address and pass it here.StringYes
billing_addressBilling address provided by the customer in Google Pay. Preprocess and map it to the Revolut Address format before sending.ObjectYes
shipping_addressShipping address provided by the customer in Google Pay. Preprocess and map it to the Revolut Address format before sending.ObjectNo
environmentObject containing information about the environment where the customer makes the payment.

This information is required for the 3DS challenge, since some banks might execute different challenges based on the object's parameters.
ObjectYes

Address object:

ParameterDescriptionRequired
street_line_1Street line 1 information.No
street_line_2Street line 2 information.No
regionThe region associated with the address.No
cityThe city associated with the address.No
country_codeThe country associated with the address (ISO 3166-1 alpha-2).Yes
postcodeThe postcode associated with the address.Yes

Environment object:

Info

Locale should be provided in <language> or <language>-<country> format, where language is an ISO 639-1 code and country is an ISO 3166-1 alpha-2 code.

ParameterDescriptionFormatRequired
typeType of the environment where payment takes place. Currently, only browser is supported.StringYes
time_zone_utc_offsetThe offset between the customer's current time zone and UTC in minutes.IntegerYes
color_depthSupported color depth of the customer's device. If in doubt, use the default value of 48.IntegerYes
screen_widthWidth of the screen where checkout is presented in pixels.IntegerYes
screen_heightHeight of the screen where checkout is presented in pixels.IntegerYes
java_enabledIndicates whether Java is enabled on the checkout screen. If in doubt, set to false.BooleanYes
challenge_window_widthThe desired width of the challenge window in pixels. A recommended ratio is 1/3 of the screen_width.IntegerNo
browser_urlThe URL of the checkout page where the challenge will be displayed.StringYes
client_ipThe IP address of the customer's device.StringNo
user_agentThe user agent string of the customer's browser or app.StringNo
accept_headerThe Accept header from the customer's HTTP request.StringNo
localeThe locale of the customer's device in <language> or <language>-<country> format.StringNo

5. Handle payment results and track status

After sending the payment request in Step 4, you need to track the payment status and handle different scenarios.

The recommended approach for tracking payment status is to use webhooks. Webhooks provide reliable, server-to-server notifications about order and payment lifecycle events and ensure you don't miss any status updates.

Info

For detailed information on setting up webhooks, see: Use webhooks to track order and payment lifecycle.

While the immediate payment response is useful for updating your app's UI, webhooks are your source of truth for the actual payment status. Your backend should listen for webhook events to determine the next action for each payment.

In the majority of cases, the response for a Google Pay payment initiated on a mobile device will be a successful transaction. This is because Google Pay usually removes the need for authentication.

However, there are scenarios where the payment might require a 3DS challenge:

  • Google Pay and/or the issuer have not been able to generate a fully authenticated payment token.
  • The transaction was soft declined by the issuer and re-authentication is required to confirm the transaction. Revolut has a mechanism to automatically retry the transaction after a soft decline and enforce 3DS authentication.

You should handle the following scenarios:

This is the most common scenario for Google Pay payments. The payment completes successfully without requiring additional authentication.

Webhooks expected:

Webhook eventDescription
ORDER_AUTHORISEDThe payment has been authorised
ORDER_COMPLETEDThe payment has been captured and completed

What to do:

  1. When you receive the ORDER_COMPLETED webhook, fulfil the order (ship goods, grant access, etc.).
  2. Depending on how you capture orders:
    • For automatic capture mode, wait for ORDER_COMPLETED before fulfiling the order.
    • For manual capture mode, ORDER_AUTHORISED can be considered a final successful state. You can now capture the order manually when ready. The ORDER_COMPLETED webhook will be sent after you capture.
Tip

Most Google Pay payments on mobile will follow the frictionless flow, as Google Pay typically removes the need for authentication.

Implementation checklist

Before deploying your implementation to your production environment, complete the checklist below to ensure everything works as expected:

Info

For a comprehensive list of integration requirements, refer to the Google Pay Android integration checklist.

  • Configured and verified an HTTPS App Link for 3ds_redirect_uri.
  • Successfully created an order using the Merchant API and received the order token.
  • Configured Google Pay button with the correct gateway parameters: gateway: "revolut" and gatewayMerchantId: <order_token>.
  • Verified that the gatewayMerchantId is dynamically set to the order token for each new payment.
  • Successfully processed a test payment and handled the payment response.
  • Set up webhook URLs on your server to receive order and payment updates.
  • Implemented webhook handling logic to track payment status based on events (ORDER_COMPLETED, ORDER_AUTHORISED, ORDER_PAYMENT_AUTHENTICATION_CHALLENGED, etc.).
  • Verified that webhooks for successful payments (ORDER_COMPLETED) trigger order fulfillment.
  • Verified that webhooks for authentication challenges (ORDER_PAYMENT_AUTHENTICATION_CHALLENGED) trigger retrieval and handling of the authentication_challenge object.
  • Handled three_ds challenges by redirecting to acs_url or loading in a WebView.
  • Handled three_ds_fingerprint challenges by decoding fingerprint_html from base64 and loading the resulting HTML in a WebView.
  • Tested both successful and declined payment scenarios in Sandbox using the Google Pay test amounts.
  • Implemented proper error handling for failed payments and displayed appropriate messages to users.
Success

Congratulations! You've successfully integrated direct Google Pay with the Revolut Merchant API in your Android app.


What's next

Was this page helpful?