google pay on android.md

Google Pay on Android

Accept Google Pay in your Android application using Finix.

This guide details how to get started accepting Google Pay on Android devices using Finix.

Dues and Assessments

We recommend that you pass the address field listed in the steps below. If the address is not passed, you will be charged additional dues and assessments per transaction from the card network.

Step 1: Onboard with Google

Start by familiarizing yourself with the prerequisites for using Google Pay with Finix.

Step 2: Define Google Pay API Version

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 properties that are present in all other request objects.

Kotlin

private val baseRequest = JSONObject()
    .put("apiVersion", 2)
    .put("apiVersionMinor", 0)

Java

private static JSONObject getBaseRequest() throws JSONException {
  return new JSONObject()
      .put("apiVersion", 2)
      .put("apiVersionMinor", 0);
}

Step 3: Request a Finix Payment Token

Now that you've defined your Google Pay API Version, request a Finix payment token.

Kotlin

private fun gatewayTokenizationSpecification(): JSONObject {
    return JSONObject().apply {
        put("type", "PAYMENT_GATEWAY")
        put("parameters", JSONObject(mapOf(
                "gateway" to "finix",
                "gatewayMerchantId" to "IDxxx")))
    }
}

Java

private static JSONObject getGatewayTokenizationSpecification() throws JSONException {
  return new JSONObject()
      .put("type", "PAYMENT_GATEWAY")
      .put("parameters", new JSONObject()
          .put("gateway", "finix")
          .put("gatewayMerchantId", "IDxxx")
      );
}

Step 4: Define Allowed Card Networks

Now that we've requested a Finix payment token, you can set which card networks will be accepted on your site.

Kotlin

private val allowedCardNetworks = JSONArray(listOf(
        "AMEX",
        "DISCOVER",
        "INTERAC",
        "JCB",
        "MASTERCARD",
        "VISA"))

Java

private static JSONArray getAllowedCardNetworks() {
  return new JSONArray()
      .put("AMEX")
      .put("DISCOVER")
      .put("INTERAC")
      .put("JCB")
      .put("MASTERCARD")
      .put("VISA");
}

Defining allowedCardAuthMethods sets the authentication methods supported by your site and gateway.

Kotlin

private val allowedCardAuthMethods = JSONArray(listOf(
        "PAN_ONLY",
        "CRYPTOGRAM_3DS"))

Java

private static JSONArray getAllowedCardAuthMethods() {
  return new JSONArray()
      .put("PAN_ONLY")
      .put("CRYPTOGRAM_3DS");
}

For both PAN_ONLY and CRYPTOGRAM_3DS authorization methods, support for 3D Secure is dictated by the processors you integrate with in allowedCardNetworks. Finix accepts both PAN_ONLY and CRYPTOGRAM_3DS authorization methods.

Step 5: Describe Allowed Payment Methods

After you've defined the supported payment card networks, you need to describe your allowed payment methods. You can do this with the following steps:

  1. Combine allowedAuthMethods and allowedCardNetworks to describe how your application supports the CARD payment method.
  2. Extend the baseCardPaymentMethod object and describe the information you expect to be returned to your application. Include a description of the tokenized payment data.

Kotlin

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)

Java

private static JSONObject getBaseCardPaymentMethod() throws JSONException {
  return new JSONObject()
      .put("type", "CARD")
      .put("parameters", new JSONObject()
          .put("allowedAuthMethods", getAllowedCardAuthMethods())
          .put("allowedCardNetworks", getAllowedCardNetworks())
          .put("billingAddressRequired", true)
          .put("billingAddressParameters", new JSONObject()
              .put("format", "FULL")
          )
      );
}
private static JSONObject getCardPaymentMethod() throws JSONException {
  return getBaseCardPaymentMethod()
      .put("tokenizationSpecification", getGatewayTokenizationSpecification());
}

Step 6: Create a PaymentsClient Instance

Create a PaymentsClient instance to interact with the Google Pay API.

Kotlin

fun createPaymentsClient(context: Context): PaymentsClient {
    val walletOptions = Wallet.WalletOptions.Builder()
        .setEnvironment(Constants.PAYMENTS_ENVIRONMENT)
        .build()

return Wallet.getPaymentsClient(context, walletOptions)
}

Java

public static PaymentsClient createPaymentsClient(Context context) {
  Wallet.WalletOptions walletOptions =
      new Wallet.WalletOptions.Builder().setEnvironment(Constants.PAYMENTS_ENVIRONMENT).build();
  return Wallet.getPaymentsClient(context, walletOptions);
}

Step 7: Check Readiness to Pay with Google Pay

Now that you've described your allowed payment methods, you need to check readiness to pay with the Google Pay API. To check readiness to pay with Google Pay's API:

  1. Add allowedPaymentMethods to the baseRequest object.
  2. Call isReadyToPay() to determine if the user can make payments with the Google Pay API.

Kotlin

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
    val task = paymentsClient.isReadyToPay(request)
    task.addOnCompleteListener { completedTask ->
        try {
            completedTask.getResult(ApiException::class.java)?.let(::setGooglePayAvailable)
        } catch (exception: ApiException) {
            Log.w("isReadyToPay failed", exception)
        }
    }
}

Kotlin (coroutines)

private suspend fun fetchCanUseGooglePay(): Boolean {
    val request = IsReadyToPayRequest.fromJson(PaymentsUtil.isReadyToPayRequest().toString())
    return paymentsClient.isReadyToPay(request).await()
}

Java

public static JSONObject getIsReadyToPayRequest() {
  try {
    return getBaseRequest()
        .put("allowedPaymentMethods", new JSONArray().put(getBaseCardPaymentMethod()));
  } catch (JSONException e) {
    return null;
  }
}

private void possiblyShowGooglePayButton() {
  final Optional<JSONObject> isReadyToPayJson = PaymentsUtil.getIsReadyToPayRequest();
  if (!isReadyToPayJson.isPresent()) {
    return;
  }
  IsReadyToPayRequest request = IsReadyToPayRequest.fromJson(isReadyToPayJson.get().toString());
  Task<Boolean> task = paymentsClient.isReadyToPay(request);
  task.addOnCompleteListener(this,
      new OnCompleteListener<Boolean>() {
        @Override
        public void onComplete(@NonNull Task<Boolean> task) {
          if (task.isSuccessful()) {
            setGooglePayAvailable(task.getResult());
          } else {
            Log.w("isReadyToPay failed", task.getException());
          }
        }
      });
}

Step 8: Add Google Pay Button

Now that you've checked readiness to pay with Google Pay API, you can add a Google Pay payment button to your website.

Kotlin (compose)

PayButton(
    modifier = Modifier
        .testTag("payButton")
        .fillMaxWidth(),
    onClick = onGooglePayButtonClick,
    allowedPaymentMethods = PaymentsUtil.allowedPaymentMethods.toString()
)

Jetpack Compose Element Note: 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

XML

<com.google.android.gms.wallet.button.PayButton
        android:id="@+id/googlePayButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"/>

If you’re adding the Google Pay button via XML, be sure to initialize it in your Android activity along with other UI elements.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

layout = ActivityCheckoutBinding.inflate(layoutInflater)
  setContentView(layout.root)

googlePayButton = layout.googlePayButton
  googlePayButton.initialize(
      ButtonOptions.newBuilder()
          .setAllowedPaymentMethods(PaymentsUtil.allowedPaymentMethods.toString()).build()
  )
  googlePayButton.setOnClickListener { requestPayment() }
  model.canUseGooglePay.observe(this, Observer(::setGooglePayAvailable))
}

Java

private void initializeUi() {
  ActivityCheckoutBinding layoutBinding = ActivityCheckoutBinding.inflate(getLayoutInflater());
  setContentView(layoutBinding.getRoot());

googlePayButton = layoutBinding.googlePayButton;
  try {
    googlePayButton.initialize(
        ButtonOptions.newBuilder()
            .setAllowedPaymentMethods(PaymentsUtil.getAllowedPaymentMethods().toString()).build()
    );
    googlePayButton.setOnClickListener(this::requestPayment);
  } catch (JSONException e) {
    // Keep Google Pay button hidden
  }
}

Step 9: Create a Payment Data Request

After creating a Google Pay payment button, you need to create a PaymentDataRequest object. The PaymentDataRequest takes in information about the merchant and transaction which is required to start the payment process with Google Pay.

Kotlin

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")

Java

private static JSONObject getTransactionInfo(String price) throws JSONException {
  return new JSONObject()
      .put("totalPrice", price)
      .put("totalPriceStatus", "FINAL")
      .put("countryCode", Constants.COUNTRY_CODE)
      .put("currencyCode", Constants.CURRENCY_CODE)
      .put("checkoutOption", "COMPLETE_IMMEDIATE_PURCHASE");
}

private static JSONObject getMerchantInfo() throws JSONException {
  return new JSONObject().put("merchantName", "Example Merchant");
}

getTransactionInfo Request 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 an optional decimal precision of two decimal places.
totalPriceStatus string, required The status of the total price used. Pass FINAL if the total price doesn't change from the amount presented to the buyer. Pass ESTIMATED if the total price might adjust based on the details of the response, such as sales tax collected that's based on a billing address. Pass NOT_CURRENTLY_KNOWN when using totalPriceStatus for a capability check.

getMerchantInfo Request 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 LIVE
merchantName string, required Pass in the name of the Merchant.

Strong Customer Authentication (SCA) Merchants that process transactions in the European Economic Area (EEA) or any other countries that are 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 supported by your application, such as any configuration of additional data expected in the response. Finally, add information about the transaction and the merchant who makes the request.

Step 10: Get Buyer Identity

A buyer identity is required before you can proceed with the next steps. You can either create a new buyer identity through the Finix API, or use an existing one you’ve already created.

Buyer Identity Data All buyer Identity fields are optional. However, Finix recommends including basic information (name, email, address, and phone) to make payment operations easier.

Use an existing buyer

  1. Log in to your Finix Dashboard.
  2. In the left sidebar, select Data Resources → Identities.
  3. Search for the buyer identity you want to use.
    • Confirm the Role is Buyer.
    • Option to use filters to quickly narrow down results.
  4. Copy the Buyer Identity (e.g. IDjWktr7BPDGhz4amrPJZoXg )

Create a new buyer

Buyer Identity Request

curl -i -X POST \
  -u USfdccsr1Z5iVbXDyYt7hjZZ:313636f3-fac2-45a7-bff7-a334b93e7bda \
  https://finix.sandbox-payments-api.com/identities \
  -H 'Content-Type: application/json' \
  -H 'Finix-Version: 2022-02-01' \
  -d '{
    "entity": {
      "phone": "7145677613",
      "first_name": "John",
      "last_name": "Smith",
      "email": "finix_example@finix.com",
      "personal_address": {
        "city": "San Mateo",
        "country": "USA",
        "region": "CA",
        "line2": "Apartment 7",
        "line1": "741 Douglass St",
        "postal_code": "94114"
      }
    },
    "identity_roles": [
      "BUYER"
    ],
    "tags": {
      "key": "value"
    },
    "type": "PERSONAL"
  }'

Buyer Identity Response

{
  "id": "IDmkDvJfxZWMEK56FDFtbozo",
  "created_at": "2024-08-09T09:34:36.87Z",
  "updated_at": "2024-08-09T09:34:36.87Z",
  "application": "APgPDQrLD52TYvqazjHJJchM",
  "entity": {
    "ach_max_transaction_amount": 0,
    "amex_mid": null,
    "annual_card_volume": 0,
    "business_address": null,
    "business_name": null,
    "business_phone": null,
    "business_tax_id_provided": false,
    "business_type": null,
    "default_statement_descriptor": null,
    "discover_mid": null,
    "dob": null,
    "doing_business_as": null,
    "email": "finix_example@finix.com",
    "first_name": "John",
    "has_accepted_credit_cards_previously": false,
    "incorporation_date": null,
    "last_name": "Smith",
    "max_transaction_amount": 0,
    "mcc": null,
    "ownership_type": null,
    "personal_address": {
      "line1": "741 Douglass St",
      "line2": "Apartment 7",
      "city": "San Mateo",
      "region": "CA",
      "postal_code": "94114",
      "country": "USA"
    },
    "phone": "7145677613",
    "principal_percentage_ownership": null,
    "short_business_name": null,
    "tax_authority": null,
    "tax_id_provided": false,
    "title": null,
    "url": null
  },
  "identity_roles": [],
  "tags": {
    "key": "value"
  },
  "type": "PERSONAL",
  "_links": {
    "self": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo"
    },
    "verifications": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/verifications"
    },
    "merchants": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/merchants"
    },
    "settlements": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/settlements"
    },
    "authorizations": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/authorizations"
    },
    "transfers": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/transfers"
    },
    "payment_instruments": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/payment_instruments"
    },
    "associated_identities": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/associated_identities"
    },
    "disputes": {
      "href": "https://finix.sandbox-payments-api.com/identities/IDmkDvJfxZWMEK56FDFtbozo/disputes"
    },
    "application": {
      "href": "https://finix.sandbox-payments-api.com/applications/APgPDQrLD52TYvqazjHJJchM"
    }
  }
}

Step 11: Create a Payment Instrument

Call loadPaymentData using the Google Pay PaymentsClient object, which results in a Task object. Extract the payment token from the PaymentData result object.

Kotlin

fun getLoadPaymentDataTask(priceLabel: String): Task<PaymentData> {
    val paymentDataRequestJson = PaymentsUtil.getPaymentDataRequest(priceLabel)
    val request = PaymentDataRequest.fromJson(paymentDataRequestJson.toString())
    return paymentsClient.loadPaymentData(request)
}

Java

public Task<PaymentData> getLoadPaymentDataTask(String priceLabel) {
    JSONObject paymentDataRequestJson = PaymentsUtil.getPaymentDataRequest(priceLabel);
    if (paymentDataRequestJson == null) {
        return null;
    }

PaymentDataRequest request =
            PaymentDataRequest.fromJson(paymentDataRequestJson.toString());
    return paymentsClient.loadPaymentData(request);
}

To process the result use one of the activity result contracts in the API.

Example Payment Instrument - Google Pay

{
  "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"
    }
  }
}

Step 12: Create a Payment

Similar to other Finix transactions, after the Payment Instrument is created, you can use the instrument and create a transfer or an authorization to process transactions.

Sale

Example Transfer Request

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": "PIf8dyFFcEGBqPhaG22hPyYs",
    }'

Example Transfer Response

{
  "id": "TR29av3LN1TAGPbXscsup1tt",
  "amount": 662154,
  "tags": {},
  "state": "SUCCEEDED",
  "trace_id": "34f40e87-2599-414b-874b-f472790ff521",
  "currency": "USD",
  "application": "APgPDQrLD52TYvqazjHJJchM",
  "source": "PImE5ZhGZJNFy14DtX8wX6f6",
  "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/IDuqZpDw28f2KK6YuDk4jNLg"
    },
    "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/PIe2YvpcjvoVJ6PzoRPBK137"
    },
    "fee_profile": {
      "href": "https://finix.sandbox-payments-api.com/fee_profiles/FPvCQUcnsueN3Bc3zR1qCBG8"
    }
  }
}

Authorization

You can create an Authorization and capture it later using two separate API calls. This approach is useful if you need to first verify the payment details and then capture a specific amount at a later time.

For more details, see Creating and Capturing an Authorization.