Let buyers pay with Google Pay in your Android application, using any debit or credit card saved to their Google account.
To add Google Pay to your Android app, you configure the payment methods and tokenization your app accepts, add the Google Pay button, and request payment data. When a buyer pays, you process the resulting token with the Finix API.
After setup, buyers can complete checkout with Google Pay and you process the payment like any other Finix transaction. The examples below show both Kotlin and Java.
Finix recommends passing the address field shown in the steps below. If you do not pass the address, the card network charges additional dues and assessments per transaction.
Before you start, familiarize yourself with the Google Pay requirements for Finix, including the Finix API key, seller onboarding, and Google Pay merchant account steps.
Declare the version of the Google Pay API that your application uses. The major and minor versions affect the fields expected in each passed object and are included in the response.
Create a base request object that contains the properties present in all other request objects.
private val baseRequest = JSONObject()
.put("apiVersion", 2)
.put("apiVersionMinor", 0)Configure the tokenization specification so Google Pay returns a Finix payment token.
- Set
gatewaytofinix. - Set
gatewayMerchantIdto the application owner Identity or merchant owner Identity. To choose the appropriate Identity ID, see Choose a Merchant identifier value.
private fun gatewayTokenizationSpecification(): JSONObject {
return JSONObject().apply {
put("type", "PAYMENT_GATEWAY")
put("parameters", JSONObject(mapOf(
"gateway" to "finix",
"gatewayMerchantId" to "IDxxx")))
}
}Set which card networks your application accepts.
private val allowedCardNetworks = JSONArray(listOf(
"AMEX",
"DISCOVER",
"INTERAC",
"JCB",
"MASTERCARD",
"VISA"))Define allowedCardAuthMethods to set the authentication methods your application and gateway support.
private val allowedCardAuthMethods = JSONArray(listOf(
"PAN_ONLY",
"CRYPTOGRAM_3DS"))For both PAN_ONLY and CRYPTOGRAM_3DS authorization methods, support for 3D Secure depends on the processors you integrate with in allowedCardNetworks. Finix accepts both PAN_ONLY and CRYPTOGRAM_3DS authorization methods.
After you define the supported card networks, describe your allowed payment methods:
- Combine
allowedAuthMethodsandallowedCardNetworksto describe how your application supports theCARDpayment method. - Extend the
baseCardPaymentMethodobject with the information you expect returned to your application, including a description of the tokenized payment data.
private fun baseCardPaymentMethod(): JSONObject =
JSONObject()
.put("type", "CARD")
.put("parameters", JSONObject()
.put("allowedAuthMethods", allowedCardAuthMethods)
.put("allowedCardNetworks", allowedCardNetworks)
.put("billingAddressRequired", true)
.put("billingAddressParameters", JSONObject()
.put("format", "FULL")
)
)
private val cardPaymentMethod: JSONObject = baseCardPaymentMethod()
.put("tokenizationSpecification", gatewayTokenizationSpecification())Create a PaymentsClient instance to interact with the Google Pay API.
fun createPaymentsClient(context: Context): PaymentsClient {
val walletOptions = Wallet.WalletOptions.Builder()
.setEnvironment(Constants.PAYMENTS_ENVIRONMENT)
.build()
return Wallet.getPaymentsClient(context, walletOptions)
}After you describe your allowed payment methods, check readiness to pay with the Google Pay API:
- Add
allowedPaymentMethodsto thebaseRequestobject. - Call
isReadyToPay()to determine whether the user can pay with the Google Pay API.
fun isReadyToPayRequest(): JSONObject? =
try {
baseRequest
.put("allowedPaymentMethods", JSONArray().put(baseCardPaymentMethod()))
} catch (e: JSONException) {
null
}
private fun possiblyShowGooglePayButton() {
val isReadyToPayJson = PaymentsUtil.isReadyToPayRequest() ?: return
val request = IsReadyToPayRequest.fromJson(isReadyToPayJson.toString()) ?: return
// The call to isReadyToPay is asynchronous and returns a Task. We need to provide an
// OnCompleteListener to be triggered when the result of the call is known.
val task = paymentsClient.isReadyToPay(request)
task.addOnCompleteListener { completedTask ->
try {
completedTask.getResult(ApiException::class.java)?.let(::setGooglePayAvailable)
} catch (exception: ApiException) {
// Process error
Log.w("isReadyToPay failed", exception)
}
}
}
After you check readiness to pay, add a Google Pay payment button to your app.
- For the different button types and display requirements, see Google's brand guidelines.
- To try every Google Pay button, see Google Pay's interactive demo.
PayButton(
modifier = Modifier
.testTag("payButton")
.fillMaxWidth(),
onClick = onGooglePayButtonClick,
allowedPaymentMethods = PaymentsUtil.allowedPaymentMethods.toString()
)To use the Jetpack Compose element, add the com.google.pay.button:compose-pay-button library to the list of dependencies in your Gradle build file. For more information, see Google Pay payment button.
If you add the Google Pay button with XML, initialize it in your Android activity along with your other UI elements.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use view binding to access the UI elements
layout = ActivityCheckoutBinding.inflate(layoutInflater)
setContentView(layout.root)
// Setup buttons
googlePayButton = layout.googlePayButton
googlePayButton.initialize(
ButtonOptions.newBuilder()
.setAllowedPaymentMethods(PaymentsUtil.allowedPaymentMethods.toString()).build()
)
googlePayButton.setOnClickListener { requestPayment() }
// Check Google Pay availability
model.canUseGooglePay.observe(this, Observer(::setGooglePayAvailable))
}After you add the Google Pay button, create a PaymentDataRequest object. The PaymentDataRequest takes in the merchant and transaction information required to start the payment process with Google Pay.
private fun getTransactionInfo(price: String): JSONObject =
JSONObject()
.put("totalPrice", price)
.put("totalPriceStatus", "FINAL")
.put("countryCode", Constants.COUNTRY_CODE)
.put("currencyCode", Constants.CURRENCY_CODE)
private val merchantInfo: JSONObject =
JSONObject().put("merchantName", "Example Merchant")The getTransactionInfo object accepts the following arguments.
| Field | Type | Description |
|---|---|---|
countryCode | string, required | The ISO country code. |
currencyCode | string, required | The currency code of the locale. |
totalPrice | string, required | Total value of the transaction, with optional decimal precision of two places. |
totalPriceStatus | string, required | The status of the total price. Pass FINAL if the total price does not change from the amount presented to the buyer. Pass ESTIMATED if the total price might adjust based on the response, such as sales tax based on a billing address. Pass NOT_CURRENTLY_KNOWN when using totalPriceStatus for a capability check. |
The getMerchantInfo object accepts the following arguments.
| Field | Type | Description |
|---|---|---|
merchantId | string, required | A Google merchant identifier issued after registration with the Google Pay Business Console. Required when PaymentsClient is initialized with an environment property of PRODUCTION. |
merchantName | string, required | The name of the Merchant. |
Merchants that process transactions in the European Economic Area (EEA) or any other region subject to Strong Customer Authentication (SCA) must include the countryCode, totalPrice, and merchantName parameters to meet SCA requirements.
Assign your base request object to a new PaymentDataRequest JSON object. Then add the payment methods your application supports, along with any configuration of additional data expected in the response. Finally, add the transaction and merchant information for the request. For more information, see Step 5 of Google Pay integration.
A Buyer Identity is required before you can process a payment. You can create a new Buyer Identity with the Finix API, or use an existing one.
All Buyer Identity fields are optional. Finix recommends including basic information (name, email, address, and phone) to make payment operations easier.
To find and reuse an existing Buyer Identity:
- Log in to your Finix Dashboard.
- In the left sidebar, select Data Resources → Identities.
- Search for the Buyer Identity you want to use, and confirm its Role is Buyer.
- Copy the Buyer Identity ID (for example,
IDjWktr7BPDGhz4amrPJZoXg).
Call loadPaymentData using the Google Pay PaymentsClient object, which returns a Task object. Extract the payment token from the PaymentData result object. For more information, see Step 6 of Google Pay integration.
fun getLoadPaymentDataTask(priceLabel: String): Task<PaymentData> {
val paymentDataRequestJson = PaymentsUtil.getPaymentDataRequest(priceLabel)
val request = PaymentDataRequest.fromJson(paymentDataRequestJson.toString())
return paymentsClient.loadPaymentData(request)
}To process the result, use one of the activity result contracts in the API. For more information, see Step 6 of Google Pay integration.
Before you present the buyer with a confirmation of their purchase, extract the payment token from the PaymentData result object and use it in the Payment Instrument request below.
Pass the third_party_token, name, and billing address that Google Pay returns when creating a Payment Instrument.
- Sandbox serverhttps://finix.sandbox-payments-api.com/payment_instruments
curl -i -X POST \
-u USfdccsr1Z5iVbXDyYt7hjZZ:313636f3-fac2-45a7-bff7-a334b93e7bda \
https://finix.sandbox-payments-api.com/payment_instruments \
-H 'Content-Type: application/json' \
-H 'Finix-Version: 2022-02-01' \
-d '{
"address": {
"city": "San Francisco",
"country": "USA",
"line1": "900 Metro Center Blv",
"line2": "APT 200",
"postal_code": "94404",
"region": "CA"
},
"identity": "ID78Fh8mcnnzukVzbdoyex5y",
"merchant_identity": "IDwhCCvPwCDEmiFd8Be7pDzN",
"name": "Finix Sandbox",
"third_party_token": "{\"signature\":\"MEYCIQCYTkaEMgug7pcjzEEdbIn+R57kYO5yYc2KYj41AQQn9wIhAN1QvylvZ2XydVecfejwi2xYS9y3Y9y/MmDnRnUfNw5H\",\"intermediateSigningKey\":{\"signedKey\":\"{\\\"keyValue\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4xc3fjeM9SMTjd1TL2GQCPmgqPf2h42aM3akPh/mTUBqWEgOITruK10A02rQ+4YZOvLCpQKQZzLSAd09nctnuA\\\\u003d\\\\u003d\\\",\\\"keyExpiration\\\":\\\"1648843199734\\\"}\",\"signatures\":[\"MEQCICwCI4s5YCLu4qRCyXwSJ3qG8y3ocFtP1Mque4Uzysl8AiARoD/0qbj5W0Q2PWKpxkEnfcP+nU5kwYS8FyQ9boDTmQ\\u003d\\u003d\"]},\"protocolVersion\":\"ECv2\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"roD4ikTpZ7Srunq+0zUnp+eiXzcuZBfIFSuZAJu1PQLXcP0RvnGDiGKtoarNCHvn+cnXsHCzIBWXMZSJ9Aglqky9VfP5a+qsXQhf5m5AFUbT2xnihtKwageGQQK6HzyjHSXXSjvuCzeo75ToOgIUxLFASZyaZ89u3Jifqhhc2c4a0Mtlx564BxXiwcxDFdtNkOle7uAIsJzsryk7Rcwgr8ZMJJM//XpvaeE5wNmkVFHUtR2uTqPm0BvkoYkFHCTRo4NHXWpxeLjXWzKGk2ELyTK1diuCa6c9ig0jO3t8BIh1cR63UeP8Ar7u5fh8C9FPPAsgPbTGLfiaRe615e4SxASgcZ4/8uWo5mikEPFqA5s2K2mid9ncXoMNYaHUc3qzJAyxHVYSd5SRNZYXHMkEcWcjnpDx+ErYjR1sMo1LMYXfrfGyZz3M69bQLKPYFe7ChjvgFI9MnfcFTNB4HAdNKMhbZT0EKinfxxGWkT7LVbGnUuqPlHp4toCe4kpbx7fulwXTj3bAFvg/qvxxwGOS38iP0HR/f+4GF0xHspqYVbdWdIJ5iJUdpBG8Nu5P56h2GEDxXMkKSmh+qbvKWlYipNNGoeg8uHc\\\\u003d\\\",\\\"ephemeralPublicKey\\\":\\\"BMqIyb1IyXhuZ4YpWm1PiRr74i3tCwDfQqJ1P4OZ3zK4Rq16SuwgJ605fCEvlViwSQuo2Hpv+CcR+2D3+/YrLB8\\\\u003d\\\",\\\"tag\\\":\\\"5K4LlTucDK7jAThbIozYtyoxX95hRNd5cJJGfxWAxw8\\\\u003d\\\"}\"}",
"type": "GOOGLE_PAY"
}'A successful request returns the newly created Payment Instrument, which you use to process the payment.
{
"id": "PIwpqpJZCharsZAt6WKVopPS",
"created_at": "2025-05-08T18:44:58.56Z",
"updated_at": "2025-05-08T18:44:58.56Z",
"application": "APc9vhYcPsRuTSpKD9KpMtPe",
"created_via": "API",
"currency": "USD",
"disabled_code": null,
"disabled_message": null,
"enabled": true,
"fingerprint": "FPR88YBDbK4TqYMUNU8t8fbeQ",
"identity": "IDmj1yA97RS4rMjiQgvK3Vio",
"instrument_type": "APPLE_PAY",
"address": {
"line1": "900 Metro Center Blv",
"line2": "APT 200",
"city": "San Francisco",
"region": "CA",
"postal_code": "94404",
"country": "USA"
},
"bin": "370382",
"brand": "AMERICAN_EXPRESS",
"card_type": "CREDIT",
"expiration_month": 11,
"expiration_year": 2024,
"issuer_country": "USA",
"last_four": "8576",
"name": "John Smith",
"tags": {},
"third_party": null,
"third_party_token": null,
"type": "GOOGLE_PAY",
"_links": {
"self": {
"href": "https://finix.sandbox-payments-api.com/payment_instruments/PIwpqpJZCharsZAt6WKVopPS"
},
"authorizations": {
"href": "https://finix.sandbox-payments-api.com/payment_instruments/PIwpqpJZCharsZAt6WKVopPS/authorizations"
},
"transfers": {
"href": "https://finix.sandbox-payments-api.com/payment_instruments/PIwpqpJZCharsZAt6WKVopPS/transfers"
},
"verifications": {
"href": "https://finix.sandbox-payments-api.com/payment_instruments/PIwpqpJZCharsZAt6WKVopPS/verifications"
},
"application": {
"href": "https://finix.sandbox-payments-api.com/applications/APc9vhYcPsRuTSpKD9KpMtPe"
},
"identity": {
"href": "https://finix.sandbox-payments-api.com/identities/IDmj1yA97RS4rMjiQgvK3Vio"
}
}
}For security, Google Pay tokens are active for only a short period of time. The third_party_token in the request above has expired. To test the request, use your own third_party_token and Finix credentials.
After the Payment Instrument is created, use it to create a Transfer or an Authorization, the same as any other Finix transaction.
To process a sale:
- Set the
sourceto the buyer's Payment Instrument ID. - Set the
merchantto anAPPROVEDMerchant account. - Set the
amountin cents.
curl https://finix.sandbox-payments-api.com/transfers \
-H "Content-Type: application/json" \
-H 'Finix-Version: 2022-02-01' \
-u USsRhsHYZGBPnQw8CByJyEQW:8a14c2f9-d94b-4c72-8f5c-a62908e5b30e \
-d '{
"merchant": "MUeDVrf2ahuKc9Eg5TeZugvs",
"currency": "USD",
"amount": 662154,
"source": "PIwpqpJZCharsZAt6WKVopPS"
}'{
"id": "TR29av3LN1TAGPbXscsup1tt",
"amount": 662154,
"tags": {},
"state": "SUCCEEDED",
"trace_id": "34f40e87-2599-414b-874b-f472790ff521",
"currency": "USD",
"application": "APgPDQrLD52TYvqazjHJJchM",
"source": "PIwpqpJZCharsZAt6WKVopPS",
"destination": null,
"ready_to_settle_at": null,
"externally_funded": "UNKNOWN",
"fee": 0,
"statement_descriptor": "FNX*FINIX FLOWERS",
"type": "DEBIT",
"messages": [],
"raw": null,
"created_at": "2022-08-25T20:39:37.59Z",
"updated_at": "2022-08-25T20:39:38.17Z",
"idempotency_id": null,
"merchant": "MUeDVrf2ahuKc9Eg5TeZugvs",
"merchant_identity": "IDpYDM7J9n57q849o9E9yNrG",
"subtype": "API",
"failure_code": null,
"failure_message": null,
"additional_buyer_charges": null,
"_links": {
"application": {
"href": "https://finix.sandbox-payments-api.com/applications/APgPDQrLD52TYvqazjHJJchM"
},
"self": {
"href": "https://finix.sandbox-payments-api.com/transfers/TR29av3LN1TAGPbXscsup1tt"
},
"merchant_identity": {
"href": "https://finix.sandbox-payments-api.com/identities/IDpYDM7J9n57q849o9E9yNrG"
},
"payment_instruments": {
"href": "https://finix.sandbox-payments-api.com/transfers/TR29av3LN1TAGPbXscsup1tt/payment_instruments"
},
"reversals": {
"href": "https://finix.sandbox-payments-api.com/transfers/TR29av3LN1TAGPbXscsup1tt/reversals"
},
"fees": {
"href": "https://finix.sandbox-payments-api.com/transfers/TR29av3LN1TAGPbXscsup1tt/fees"
},
"disputes": {
"href": "https://finix.sandbox-payments-api.com/transfers/TR29av3LN1TAGPbXscsup1tt/disputes"
},
"source": {
"href": "https://finix.sandbox-payments-api.com/payment_instruments/PIwpqpJZCharsZAt6WKVopPS"
},
"fee_profile": {
"href": "https://finix.sandbox-payments-api.com/fee_profiles/FPvCQUcnsueN3Bc3zR1qCBG8"
}
}
}Alternatively, create an Authorization and capture it later with two separate API calls. This is useful when you need to verify the payment details first and capture a specific amount later. For more information, see Creating and capturing an Authorization.