Google Pay via Widget

This guide walks you through integrating Google Pay using the DEUNA SKDs. It covers the two integration paths the SDK exposes:

Payment WidgetPayment Vault
What it does**Handles the full checkout: UI, payment processing, and confirmationTokenizes the card only — returns a card_id for you to use
Who processes the purchaseDEUNA (internally)You (via the Purchase API from your backend)
Google Pay buttonRendered inside DEUNA's iframeRendered by you, in your own UI
SDK methodinitPaymentWidgetinitElements({ types: ['GOOGLE_PAY'] })
Use whenYou want a drop-in checkout experienceYou need control over the payment flow or want to store the card for later

1. Prerequisites

Before you start, make sure the following are in place:

RequirementNotes
DEUNA accountActive merchant account in the DEUNA Dashboard.
publicApiKeyPublic API key issued by DEUNA. Required for DeunaSDK.initialize.
orderTokenGenerated on your backend via the DEUNA Orders API. Required to start a payment.
userToken (optional)Required only when you want to tokenize the card against a known DEUNA user.
Compatibility requirementsRefer to the official Google Pay supported devices guide. Google Pay supports Chrome, Firefox, Safari, Edge, Opera, and UC Browser. For Android WebView integrations, additional requirements apply — see the Android WebView guide

2. What needs to be pre‑configured for Google Pay

The setup has two parts: credentials and, for production, domain registration inside the Google Pay Business Console.

2.1 Credentials (handled by DEUNA)

DEUNA resolves Google Pay credentials from your merchant configuration. The fields involved are:

FieldMeaningWhere it comes from
merchantIdYour Google Pay Merchant ID (e.g. 12345678901234567890).Google Pay Business Console, stored in DEUNA Dashboard.
merchantNameLabel shown on the Google Pay sheet.DEUNA Dashboard.
gatewayPayment gateway identifier (e.g. "deuna", "adyen"). Used with PAYMENT_GATEWAY tokenization.DEUNA Dashboard.
gatewayMerchantIdMerchant identifier within the gateway.DEUNA Dashboard.
tokenizationType"PAYMENT_GATEWAY" (default) or "DIRECT".Merchant choice.
publicKey (DIRECT only)Base64‑encoded public key used for DIRECT tokenization.DEUNA Dashboard.
protocolVersion (DIRECT only)Defaults to "ECv2".DEUNA Dashboard.
allowedCardNetworksSubset of VISA, MASTERCARD, AMEX, DISCOVER, INTERAC, JCB.Optional — defaults provided.
allowedCardAuthMethodsPAN_ONLY, CRYPTOGRAM_3DS.Optional — defaults provided.

Most integrations will use PAYMENT_GATEWAY tokenization with DEUNA as the gateway. DIRECT is reserved for merchants that decrypt the Google Pay token themselves.

What you need to provide/confirm in the DEUNA Dashboard:

  1. Google Pay credential enabled for your merchant.
  2. Merchant ID and merchant name.
  3. Gateway and gateway merchant ID (for PAYMENT_GATEWAY).
  4. Allowed networks and auth methods (optional).

2.2 Domain registration (production only)

Google Pay requires that every production domain be registered in the Google Pay Business Console before it can take live payments:

  • Go to Google Pay & Wallet Console → Integration → Business information.
  • Register the domain(s) that will load the Web‑SDK (e.g. checkout.mystore.com).
  • Submit your integration for approval (screenshots of the checkout flow are required).

No file needs to be hosted on your domain. Test/sandbox environments work out of the box — only production requires the console registration.

The SDK automatically switches Google Pay to TEST mode for any env other than "production", so you can develop and QA without console registration.


📘

For the full widget integration guide, including initialization, callbacks, and display options.

Google Pay particularities

  • No extra configuration needed in code.
  • Google Pay is enabled or disabled from the DEUNA Dashboard. If the merchant has it active and the user's browser supports it, the button appears automatically.
  • userToken is optional — only needed when you want to associate the payment with a known DEUNA user account.
  • The standard widget callbacks (onSuccess, onError, onClosed, onPaymentProcessing) work the same way as for other payment methods.
  • The SDK automatically calls isReadyToPay and hides the button on unsupported devices — no additional check is required on your side.

What the commerce must do for Google Pay

This is the checklist the merchant (commerce) owns:

  • Chrome, Edge, Firefox, Safari (any evergreen browser). User must be signed into a Google account with a saved card.
  • Serve the checkout over HTTPS. Google Pay refuses to run on http:// except localhost.
  • Register all production domains in the Google Pay Business Console. Staging/dev hosts don't need registration because the SDK runs Google Pay in TEST mode there.
  • Complete the Google Pay brand‑compliance review. Upload screenshots of the full checkout (button on cart, payment sheet, confirmation) in the Business Console.
  • Do not modify the Google Pay token. The SDK forwards paymentMethodData unchanged to onPaymentAuthorized / onSuccess. Re‑serializing it will break tokenization.

3. Integrations

Make sure to follow the Getting Started guide for our SDKs depending on your specific integration:


3.1 Payment Widget

Use this path when you want DEUNA to handle the full checkout experience (UI, payment processing, and confirmation).

Web SDK

No Extra Configuration Required: You do not need to manually include Google’s scripts. The Web SDK dynamically loads the Google Pay JavaScript SDK (pay.js) the moment initPaymentWidget is called.

📘

Respect the user gesture. When using initElements, the button click must reach loadPaymentData() without a long await in between, or Chrome will block the sheet.

Android SDK

In Android, Google Pay is enabled via PaymentRequest within the WebView used by the DEUNA SDK. The host app must apply the following configuration:

  • Add the following to your app module's build.gradle or build.gradle.kts:
    dependencies {
        implementation("androidx.webkit:webkit:1.14.0")
    }
  • AndroidManifest.xml Queries: The host app must declare these intents to allow communication with Google Pay.
    <queries>
        <intent>
            <action android:name="org.chromium.intent.action.PAY" />
        </intent>
        <intent>
            <action android:name="org.chromium.intent.action.IS_READY_TO_PAY" />
        </intent>
        <intent>
            <action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
        </intent>
    </queries>
  • SDK Configuration: This configuration must be executed before calling initPaymentWidget method or rendering an embedded DeunaWidget.
    import androidx.webkit.WebSettingsCompat
    import androidx.webkit.WebViewFeature
    import com.deuna.maven.DeunaSDK
    import com.deuna.maven.shared.Environment
    
    val deunaSDK = DeunaSDK(
        environment = Environment.SANDBOX,
        publicApiKey = "YOUR_PUBLIC_API_KEY"
    )
    
    // This enables the host app to configure PaymentRequest for Google Pay support.
    deunaSDK.applyCustomWebViewSettings { settings ->
        // Guard the call to avoid crashes on devices/WebView versions that do not support PaymentRequest.
        if (WebViewFeature.isFeatureSupported(WebViewFeature.PAYMENT_REQUEST)) {
            // Enable PaymentRequest API on DEUNA's internal WebView settings.
            WebSettingsCompat.setPaymentRequestEnabled(settings, true)
        }
    }

3.2 Payment Vault

Use this path when you want to render a native Google Pay button inside your own UI (no DEUNA iframe). Common in custom/headless checkouts.

Web SDK

Let the Web SDK resolve Google Pay credentials from the DEUNA backend using your publicApiKey and (optionally) an orderToken.

For more info check the getWalletsAvailable documentation.

// 1) Initialize the SDK
await DeunaSDK.initialize({
  env: 'staging',
  publicApiKey: '<YOUR_PUBLIC_API_KEY>',
});

// 2) Check availability + warm up the Google Pay provider
const available = await DeunaSDK.getWalletsAvailable();

if (available.includes('GOOGLE_PAY')) {
  // Render button for Google Pay and append a listener (EXAMPLE)
  btn.addEventListener('click', () => {
    deuna.initElements({
      types: [{ name: 'GOOGLE_PAY' }],
      orderToken: '<order-token>', // REQUIRED FOR MERCHANTS
      userInfo: {
        email: '<email>',
        firstName: '<firstName>',
        lastName: '<lastName>',
      },
      callbacks: {
        // Called after user approves the Google Pay sheet.
        // Send the token to your backend, return the result.
        onSuccess: async (payload) => {
          const cardId = payload.data.card_id;
          // use the cardId to process payment
        },
        onError: (error) => {
          console.error('Payment failed:', error.metadata.message);
        },
      },
    });
  });
} else {
  console.error('Google Pay is not available on this device.');
}

Android SDK

Use this path when you want to render a native Google Pay sheet directly. The SDK checks device availability, fetches Google Pay credentials from the DEUNA backend, and launches the payment sheet. The result is a tokenized card payload delivered to your onSuccess callback.

Step 1 — Check availability

Call getWalletsAvailable() once, before the user reaches the payment step. The SDK checks both the DEUNA merchant configuration and whether the device has Google Play Services with a saved card.

import com.deuna.maven.DeunaSDK
import com.deuna.maven.shared.Environment
import com.deuna.maven.wallets.GetWalletsAvailableParams
import com.deuna.maven.wallets.WalletProvider
import com.deuna.maven.wallets.getWalletsAvailable

val deunaSDK = DeunaSDK(
    environment = Environment.SANDBOX,
    publicApiKey = "YOUR_PUBLIC_API_KEY",
)

deunaSDK.getWalletsAvailable(
    context = context,
    params = GetWalletsAvailableParams(
        orderToken = "<order-token>",   // optional — pass if you have one at this point
    ),
) { wallets, error ->
    if (error != null) {
        // handle fetch error
        return@getWalletsAvailable
    }
    val googlePayAvailable = WalletProvider.GOOGLE_PAY in wallets
    // show or hide your Google Pay button based on googlePayAvailable
}
📘

getWalletsAvailable() caches the result. Subsequent calls return the cached list immediately — safe to call on every screen load.

Step 2 — Launch Google Pay

When the user taps your Google Pay button, call initElements with GOOGLE_PAY as the type. The SDK fetches fresh credentials for the order, then launches the native payment sheet.

// Wire this to your Google Pay button's onClick
deunaSDK.initElements(
    context = context,
    types = listOf(mapOf("name" to "GOOGLE_PAY")),
    orderToken = "<order-token>",// required for google pay wallet
    userInfo = UserInfo(// optional — associate with a DEUNA user
        email = "[email protected]",
        firstName = "Jane",
        lastName = "Doe",
    ),
    callbacks = ElementsCallbacks().apply {
        onSuccess = { payload ->
            // payload contains the tokenized card data
            // send it to your backend to complete the purchase
        }
        onError = { error ->
            // error.metadata.code and error.metadata.message describe the failure
        }
        onClosed = { action ->
            // user dismissed the sheet
        }
    },
)

iOS SDK

Use this path when you want to render a native Apple Pay sheet directly. The SDK checks device availability, fetches Apple Pay credentials from the DEUNA backend, and launches the payment sheet. The result is a tokenized card payload delivered to your onSuccess callback.

iOS Apple Pay prerequisites

  • Enable Apple Pay capability in your app target.
  • Add the Merchant ID in Signing & Capabilities > Apple Pay.
  • Ensure the same Merchant ID is returned by DEUNA credentials (external_merchant_id).
  • In Apple Developer, that Merchant ID must have an active Apple Pay Payment Processing Certificate.
  • Regenerate provisioning profiles after capability/merchant changes and reinstall the app on a real device.

Common errors

  • APPLE_PAY_PRESENT_FAILED: Usually capability/profile/merchant certificate mismatch in the signed app.
  • MISSING_USER_AUTH: Backend did not return userToken/userId (pass valid userInfo with firstName, lastName and email).

Step 1 — Check availability Call getWalletsAvailable() once before the payment step. The SDK validates both DEUNA merchant configuration and Apple Pay availability on the device.

import DeunaSDK

let deunaSDK = DeunaSDK(
    environment: .sandbox,
    publicApiKey: "YOUR_PUBLIC_API_KEY"
)

deunaSDK.getWalletsAvailable(
    params: GetWalletsAvailableParams(
        orderToken: "<order-token>", // optional at this stage
        userInfo: DeunaSDK.UserInfo(
            email: "[email protected]",
            firstName: "Jane",
            lastName: "Doe"
        ) // recommended for wallet auth flows
    )
) { wallets, error in
    if let error = error {
        // handle fetch error
        return
    }

    let applePayAvailable = wallets.contains(.applePay)
    // show or hide your Apple Pay button based on applePayAvailable
}

getWalletsAvailable() caches the result. Subsequent calls return cached wallets immediately, so it is safe to call on each screen load.

Step 2 — Launch Apple Pay When the user taps your Apple Pay button, call initElements with APPLE_PAY as the type. The SDK fetches order credentials and launches the native Apple Pay sheet.

deunaSDK.initElements(
    userToken: "YOUR_ORDER_TOKEN", // required for apple pay wallet
    callbacks: ElementsCallbacks(
        onSuccess: { payload in
            // payload contains tokenized card data
        },
        onError: { error in
            // error.metadata?.code / message
        },
        onClosed: { _ in
            // user dismissed the sheet
        },
        onEventDispatch: nil
    ),
    closeEvents: [],
    userInfo: DeunaSDK.UserInfo(
        email: "[email protected]",
        firstName: "Jane",
        lastName: "Doe"
    ),
    styleFile: nil,
    types: [["name": "APPLE_PAY"]],
    language: nil,
    orderToken: "<order-token>",
    widgetExperience: nil,
    behavior: nil,
    fraudCredentials: nil,
    customUserAgent: nil,
    domain: nil
)

Gotchas

GotchaFix
Button does not renderCheck getWalletsAvailable() result. isReadyToPay may be rejecting the device — verify you're signed into Google and have a saved card.
Works locally, fails in productionDomain is not registered in the Google Pay Business Console.
DEVELOPER_ERROR in the sheetmerchantId, gateway, or gatewayMerchantId is wrong or missing. Double‑check the walletConfig.
Sheet opens but no payment methodsCard networks in allowedCardNetworks don't match any saved card on the Google account.
Token decryption fails on your backendYou're in DIRECT mode with a mismatched publicKey / protocolVersion. Prefer PAYMENT_GATEWAY unless you need raw card data.

Quick reference

APIPurpose
DeunaSDK.getWalletsAvailable()Check which wallets are usable + warm up providers.
DeunaSDK.initElements({ types, orderToken?, walletConfig?, callbacks })Mount native wallet buttons in your own UI.
Google Pay Business ConsoleWhere production domains must be registered. No file to host on your server.