> For the complete documentation index, see [llms.txt](https://plexo.gitbook.io/rest-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://plexo.gitbook.io/rest-api/wallets/google-pay/google-pay-android.md).

# Native Android Integration

Apple Pay and Google Pay availability comes from current Visa/Mastercard routing on every channel. See [ownership and payment-method eligibility](/rest-api/api-reference/wallet-integrations.md#wallet-ownership-and-availability) before following this guide. Use only eligible methods in `allowedCardNetworks` or `supportedNetworks`; examples listing both assume both are eligible. With `managedBy: "handy"`, Handy owns configuration and native provider setup; request changes through Handy. References to your provider credentials mean the resolved owner's credentials. Your team still validates its app/device, and the original Plexo merchant remains the recipient and Google `gatewayMerchantId`.

Use this merchant-managed flow when your native Android application renders Google Pay directly. You are responsible for registration in the Google Pay & Wallet Console, app approval, compliance with Google's branding requirements, and publishing the approved production app.

{% hint style="warning" %}
The native channel requires a real sandbox token-processing journey before production availability. Your team builds and tests its own Android app on a suitable device with its Google provider account and Plexo test merchant; Plexo does not provide a test app. Coordinate results and production approval with Plexo.
{% endhint %}

In this model:

* Your Android application renders Google Pay using Google's Android SDK
* Your application serializes the complete `paymentMethodData` object once as a JSON string and sends it to your backend
* Your backend forwards it as `paymentMethod.googlePayToken.paymentMethodData` without Base64 encoding
* Your backend either creates the payment directly or tokenizes first when installment selection is required

## Prerequisites

1. Request Google Pay activation from **Integrations > Digital Wallets** in the [Plexo Dashboard](https://dashboard.plexo.com) with:
   * `channels` includes `native`
   * `googlePayProfiles.native.profileMode = merchant`
   * your Google Merchant ID and Android package
   * `allowedAuthMethods = ["CRYPTOGRAM_3DS"]`
   * no merchant name or origin fields
2. Accept the Google Pay terms, select **Request activation**, and wait for Plexo Operations to approve the request.
3. Register your merchant in the Google Pay & Wallet Console and select the Android application associated with your Google Play account. Google currently lists Android applications published in Google Play under the same Google Account. You own Google's approval and production publishing process.
4. Prepare a backend that can authenticate with Plexo and receive the Google Pay token from the Android app over HTTPS.

The initial Plexo Native Android flow supports only `CRYPTOGRAM_3DS`. Plexo also supports `PAN_ONLY` in other Google Pay flows as described in the [Google Pay API guide](/rest-api/wallets/google-pay/google-pay-api.md#authorization-methods-and-pan_only-3ds).

## Official Google Android Resources

Use Google's documentation for Android SDK implementation and production readiness:

* [Set up Google Pay API for Android](https://developers.google.com/pay/api/android/guides/setup)
* [Google Pay Android tutorial](https://developers.google.com/pay/api/android/guides/tutorial)
* [Google Pay Android brand guidelines](https://developers.google.com/pay/api/android/guides/brand-guidelines)
* [Google Pay Android integration checklist](https://developers.google.com/pay/api/android/guides/test-and-deploy/integration-checklist)
* [Publish your Android integration](https://developers.google.com/pay/api/android/guides/test-and-deploy/publish-your-integration)

## Step 0: Check Wallet Availability

Before the Android app presents Google Pay, have your backend verify that the wallet is active for the merchant.

**Endpoint:** `GET /v1/merchants/{merchantId}/wallet-integrations`

```bash
curl -X GET "https://api.plexo.com.uy/v1/merchants/12345/wallet-integrations" \
  -u "username:password"
```

### Example Response

```json
{
  "googlePay": {
    "enabled": true,
    "channels": [{ "channel": "native", "enabled": true, "approved": true, "ready": true, "available": true, "status": "active" }]
  },
  "applePay": null
}
```

Only proceed when `googlePay.enabled` is `true` and the `native` channel is enabled, approved, ready, and available. If Google Pay is unavailable, the app should not present it as a payment option.

{% hint style="info" %}
Refresh availability before presenting checkout and after configuration or routing changes. A previously available channel can become unavailable; handle the current API rejection even if the app already displayed Google Pay.
{% endhint %}

## Step 1: Set Up the Android App

Follow Google's [Android setup guide](https://developers.google.com/pay/api/android/guides/setup) to add the Google Pay API dependency and configure your application. Then follow the [Android tutorial](https://developers.google.com/pay/api/android/guides/tutorial) to create the Google Pay client.

During development, initialize the Google Pay client with Google's test environment. Do not switch to the production environment until Google approves the application.

This guide intentionally does not duplicate Google's Kotlin or Java SDK examples. Use the current Google documentation for client construction, activity result handling, and Android lifecycle integration.

## Step 2: Configure the Android Payment Method

Define the Android `CARD` payment method with Plexo as the payment gateway:

```json
{
  "type": "CARD",
  "parameters": {
    "allowedCardNetworks": ["VISA", "MASTERCARD"],
    "allowedAuthMethods": ["CRYPTOGRAM_3DS"],
    "billingAddressRequired": true,
    "billingAddressParameters": {
      "format": "FULL"
    }
  },
  "tokenizationSpecification": {
    "type": "PAYMENT_GATEWAY",
    "parameters": {
      "gateway": "plexouy",
      "gatewayMerchantId": "<Plexo merchantId>"
    }
  }
}
```

{% hint style="warning" %}
Your Google merchant and Android app registration identify your integration to Google. `gatewayMerchantId` is a different identifier: it must be your Plexo `merchantId`, serialized as a string. Do not put a Google merchant ID, Android application ID, or internal store ID in this field.
{% endhint %}

Do not add `PAN_ONLY` to this configuration. The documented initial Native Android contract accepts only `CRYPTOGRAM_3DS`.

## Step 3: Check Readiness and Display Google Pay

Use Google's readiness check with the `CARD` parameters from Step 2. The `tokenizationSpecification` is not required for `IsReadyToPayRequest` and has no effect there. Display the Google Pay button only when the readiness result is successful and `true`.

Use Google's official Google Pay button for Android and follow the [Android brand guidelines](https://developers.google.com/pay/api/android/guides/brand-guidelines). Do not create a custom button that imitates Google Pay branding.

If the readiness result is `false`, keep the button hidden and let the customer select another payment method. This outcome is not a Plexo API error.

## Step 4: Build and Load the Payment Request

Build the Google Pay `PaymentDataRequest` with the payment method from Step 2, your merchant display name, and the final checkout amount. This language-neutral example shows the required relationship between those values:

```json
{
  "apiVersion": 2,
  "apiVersionMinor": 0,
  "merchantInfo": {
    "merchantName": "Example Store"
  },
  "allowedPaymentMethods": [
    {
      "type": "CARD",
      "parameters": {
        "allowedCardNetworks": ["VISA", "MASTERCARD"],
        "allowedAuthMethods": ["CRYPTOGRAM_3DS"],
        "billingAddressRequired": true,
        "billingAddressParameters": {
          "format": "FULL"
        }
      },
      "tokenizationSpecification": {
        "type": "PAYMENT_GATEWAY",
        "parameters": {
          "gateway": "plexouy",
          "gatewayMerchantId": "<Plexo merchantId>"
        }
      }
    }
  ],
  "transactionInfo": {
    "totalPriceStatus": "FINAL",
    "totalPrice": "100.00",
    "currencyCode": "UYU",
    "countryCode": "UY"
  },
  "emailRequired": true
}
```

Android `MerchantInfo` uses `merchantName` for the merchant name shown in the Google Pay sheet. Do not add the Google Merchant ID configured during onboarding to this Android request. Set `gatewayMerchantId` to the Plexo `merchantId`; this gateway identifier is independent of the merchant and app registration in Google Pay & Wallet Console.

Present the payment sheet by loading this request through the Google Pay Android SDK. If the customer cancels the sheet, return to checkout without calling your backend or Plexo.

## Step 5: Send the Google Pay Token to Your Backend

After Google Pay returns `PaymentData`, serialize its complete `paymentMethodData` object once with `JSONObject.toString()`. Send that JSON string to your backend over HTTPS. Do not serialize the outer response or send only `tokenizationData.token`. Supply cardholder details separately and preserve the inner token string unchanged.

```kotlin
val responseJson = requireNotNull(paymentData.toJson())
val paymentMethodDataJson = JSONObject(responseJson)
    .getJSONObject("paymentMethodData")
    .toString()
```

Forward `paymentMethodDataJson` unchanged as `paymentMethod.googlePayToken.paymentMethodData`. Serialize the enclosing HTTP request normally; do not serialize this string again. No nested DTO class is needed.

Google Pay does not return separate first-name and last-name fields. When `emailRequired` is `true`, `PaymentData.email` can provide the payer email. When billing address is requested, `paymentMethodData.info.billingAddress.name` is a single full-name value, not structured given/family names. Supply Plexo's required `cardholder.firstName` and `cardholder.lastName` from your checkout or customer data rather than assuming they can be reliably split from that full-name string.

Your backend must:

1. Receive the JSON string containing the complete `paymentMethodData` object.
2. Validate and map your checkout/customer data to `cardholder.firstName` and `cardholder.lastName`; use `PaymentData.email` for `cardholder.email` when appropriate.
3. Map the string unchanged to `paymentMethod.googlePayToken.paymentMethodData` in Steps 6 or 7.

The string must decode to an object with `type: "CARD"`, `tokenizationData.type: "PAYMENT_GATEWAY"` and a nonempty string `tokenizationData.token`. Do not Base64-encode the method JSON or the inner token. Missing, empty or malformed JSON, decoded arrays, nulls, primitives, double-encoded strings and encrypted-token-only JSON are rejected. Optional `description` and `info` accept any JSON kind; malformed display values are ignored and do not invalidate an otherwise valid processing token.

{% hint style="warning" %}
**Breaking change:** `googlePayToken.paymentMethodData` is now a string, not an object. Update your Android producer and backend mapping together; there is no object fallback or legacy token-only input. Direct payments, direct tokenization and Google Pay session flows use this JSON-string contract. See [GooglePayTokenDto](/rest-api/api-reference/models.md#googlepaytokendto). Examples use non-chargeable placeholders.
{% endhint %}

{% hint style="danger" %}
Keep all Plexo credentials in your backend; never include them in the APK. Do not log the Google Pay token, put it in a URL or analytics event, or persist it in the Android client. Send it only to your backend over HTTPS for immediate processing.
{% endhint %}

## Step 6 (Optional): Tokenize for Installment Decisions

If checkout must show installment options before charging, send the JSON string containing the complete `paymentMethodData` object to Plexo first. The response provides card type, origin and issuer for installment decisions.

**Endpoint:** `POST /v1/tokenizations`

```json
{
  "merchantId": 12345,
  "type": "temporal",
  "paymentMethod": {
    "source": "google-pay-token",
    "walletChannel": "native",
    "googlePayToken": {
      "paymentMethodData": "{\"type\":\"CARD\",\"description\":\"Visa •••• 0027\",\"info\":{\"cardNetwork\":\"VISA\",\"cardDetails\":\"0027\"},\"tokenizationData\":{\"type\":\"PAYMENT_GATEWAY\",\"token\":\"{\\\"signature\\\":\\\"PLACEHOLDER\\\",\\\"protocolVersion\\\":\\\"ECv2\\\",\\\"signedMessage\\\":\\\"PLACEHOLDER\\\"}\"}}",
      "cardholder": {
        "firstName": "John",
        "lastName": "Doe",
        "email": "john.doe@example.com"
      }
    }
  }
}
```

### Example Response

```json
{
  "token": "9b7f1c2e-4a3d-4e8b-9c1f-2d3e4f5a6b7c",
  "paymentMethodId": "visa",
  "paymentMethodType": "card",
  "tokenizationType": "temporal",
  "status": "active",
  "source": "network-token",
  "bin": "41111111",
  "last4": "1111",
  "metadata": {
    "display_name": "Visa •••• 0027",
    "display_last4": "0027"
  },
  "expMonth": 12,
  "expYear": 2030,
  "cardType": "credit",
  "cardOrigin": "uruguay",
  "issuer": {
    "id": 101,
    "name": "Banco República Oriental del Uruguay",
    "shortName": "BROU",
    "country": "Uruguay",
    "countryCode": "UY"
  },
  "expiresAt": "2025-01-16T10:30:00Z"
}
```

Use the returned `token` in Option B of Step 7. See the [Direct Tokenization guide](/rest-api/customers-and-saved-methods/tokenization-guide.md#direct-wallet-tokenization-google-pay--apple-pay) for the full tokenization contract.

{% hint style="info" %}
Skip this step when checkout does not offer installment selection. Use Option A in Step 7 instead.
{% endhint %}

## Step 7: Send the Payment to Plexo

Submit the payment from your backend through `POST /v1/payments` using one of the following request shapes.

### Option A: Pay Directly With the Google Pay Token

Use this option when you skipped Step 6. Send the complete method object serialized once as a JSON string with `paymentMethod.source = google-pay-token`.

```json
{
  "merchantId": 12345,
  "referenceId": "order-123",
  "invoiceNumber": "INV-123",
  "amount": {
    "total": 100.00,
    "currency": "UYU"
  },
  "capture": {
    "method": "automatic"
  },
  "paymentMethod": {
    "source": "google-pay-token",
    "walletChannel": "native",
    "googlePayToken": {
      "paymentMethodData": "{\"type\":\"CARD\",\"description\":\"Visa •••• 0027\",\"info\":{\"cardNetwork\":\"VISA\",\"cardDetails\":\"0027\"},\"tokenizationData\":{\"type\":\"PAYMENT_GATEWAY\",\"token\":\"{\\\"signature\\\":\\\"PLACEHOLDER\\\",\\\"protocolVersion\\\":\\\"ECv2\\\",\\\"signedMessage\\\":\\\"PLACEHOLDER\\\"}\"}}",
      "cardholder": {
        "firstName": "John",
        "lastName": "Doe",
        "email": "john.doe@example.com"
      }
    }
  }
}
```

### Option B: Pay With the Token Returned by Step 6

Use this option after tokenization and installment selection. Send the Plexo token with `paymentMethod.source = token` and include the selected installment count.

```json
{
  "merchantId": 12345,
  "referenceId": "order-123",
  "invoiceNumber": "INV-123",
  "amount": {
    "total": 100.00,
    "currency": "UYU"
  },
  "capture": {
    "method": "automatic"
  },
  "installments": 3,
  "paymentMethod": {
    "source": "token",
    "paymentInstrument": {
      "token": "9b7f1c2e-4a3d-4e8b-9c1f-2d3e4f5a6b7c"
    }
  }
}
```

### Request Fields

| Field                                            | Type    | Required                           | Description                                                                                     |
| ------------------------------------------------ | ------- | ---------------------------------- | ----------------------------------------------------------------------------------------------- |
| `merchantId`                                     | integer | Yes                                | Plexo merchant ID                                                                               |
| `referenceId`                                    | string  | Yes                                | Your transaction reference                                                                      |
| `amount.total`                                   | decimal | Yes                                | Payment amount                                                                                  |
| `amount.currency`                                | string  | Yes                                | ISO currency code                                                                               |
| `installments`                                   | integer | No                                 | Selected installment count after Step 6                                                         |
| `paymentMethod.source`                           | string  | Yes                                | `google-pay-token` for Option A or `token` for Option B                                         |
| `paymentMethod.walletChannel`                    | string  | Required for raw Google Pay tokens | `native` for Option A and Step 6; omit for Option B's Plexo token                               |
| `paymentMethod.googlePayToken.paymentMethodData` | string  | Required for Option A              | Complete Google Pay method object serialized once as JSON; decoded processing shape from Step 5 |
| `paymentMethod.googlePayToken.cardholder`        | object  | Required for Option A              | Cardholder details                                                                              |
| `paymentMethod.paymentInstrument.token`          | string  | Required for Option B              | Plexo payment instrument token returned by Step 6                                               |

## Error Behavior

Android-side outcomes and Plexo API errors occur at different points:

| Outcome                                                 | Handling                                                                           |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| The wallet availability check is disabled or missing    | Do not offer Google Pay                                                            |
| Google's readiness check returns `false`                | Hide the Google Pay button and offer another method                                |
| The customer cancels the Google Pay sheet               | Return to checkout without calling the backend or Plexo                            |
| The Google Pay Android SDK returns an integration error | Follow Google's setup and troubleshooting guidance; this is not a Plexo error code |

Common Plexo client-visible errors for this flow include:

| Error Code                    | When It Happens                                                                                                       |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `google-pay-not-enabled`      | Google Pay is not enabled for the merchant                                                                            |
| `invalid-cardholder`          | The cardholder object is missing or invalid                                                                           |
| `request-validation-errors`   | Missing, null, empty or non-string `paymentMethodData`, request JSON cannot bind, or another request field is invalid |
| `invalid-card-payment-method` | The Google Pay token fails validation or decryption checks                                                            |
| `internal-error`              | An unexpected backend failure occurs                                                                                  |

{% hint style="info" %}
Do not add `PAN_ONLY` handling or rely on invented uppercase codes such as `INVALID_GOOGLE_PAY_TOKEN`. The initial Native Android contract uses only `CRYPTOGRAM_3DS`, and Plexo responses use the published error-code contract.
{% endhint %}

## Testing

Use Google's test environment. To use Google's [test card suite](https://developers.google.com/pay/api/android/guides/resources/test-card-suite), join the Google Pay test card suite group with the account used for testing. Test at least the following before requesting production approval:

* The button is hidden when either Plexo wallet availability or Google's readiness check fails
* The official Google Pay button follows Google's branding rules
* The payment sheet shows the correct merchant name, amount, and currency
* The app serializes the complete `paymentMethodData` object once, preserving its token string without logging it
* The backend forwards the JSON string without serializing it again or Base64 encoding it and successfully completes Option A
* Wallet labels use normalized `display_last4`, not processing `last4`; missing hints show no suffix
* If you offer installments, Step 6 returns metadata and Option B uses the returned Plexo token
* Cancellation and Google SDK errors return the customer safely to checkout without creating a Plexo payment

Google's test environment does not return live, chargeable payment credentials. An unapproved application may display **Unrecognized App** during testing.

## Production Publishing

Complete Google's [Android integration checklist](https://developers.google.com/pay/api/android/guides/test-and-deploy/integration-checklist), then follow the [publishing process](https://developers.google.com/pay/api/android/guides/test-and-deploy/publish-your-integration):

1. In the Google Pay & Wallet Console, select the Android application associated with your Google Play account, choose the Gateway integration type, upload the required screenshots, and submit the integration for approval.
2. Resolve any branding or integration feedback from Google.
3. Build the approved application with its production signing key.
4. Switch the Google Pay client from the test environment to the production environment.
5. Publish the approved build through Google Play.

Do not publish a production-enabled build before Google approves the application. A debug-signed build is not valid for the production integration.

## Related Guides

For display-key locations and their unverified recognition-only meaning, see [wallet display hints](/rest-api/customers-and-saved-methods/tokenization-guide.md#wallet-display-hints).

* [Google Pay Integration Overview](/rest-api/wallets/google-pay.md)
* [API Integration](/rest-api/wallets/google-pay/google-pay-api.md)
* [Payment Processing Guide](/rest-api/payments/payment-processing.md)
* [Wallet Integrations API Reference](/rest-api/api-reference/wallet-integrations.md)
