Onerway
Payment methods

Google Pay

How Google Pay differs across Checkout, Web SDK, and Direct API, website registration before going live, choosing the merchant identifier and decryption mode, the Direct API front-end configuration and transaction flow, the two paths for PAN_ONLY tokens, wallet subscriptions, and common issues.

Google Pay lets customers check out quickly with a card saved to their Google account, in Chrome, Safari, Firefox, Edge, and other major browsers. With Checkout and the Web SDK, Onerway renders the Google Pay button and handles the token. With the Direct API, you load the Google Pay JS SDK yourself, obtain the encrypted payment token, and submit it to Onerway.

Choose an integration method

Integration methodButton and tokenWhat you do
CheckoutThe checkout page renders the button; the token never reaches your systemSubmit productType=ALL, or lpmsInfo.lpmsType=GooglePay to lock to Google Pay
Web SDKThe SDK renders the button on your page, appearance in Configure wallet buttons; the token never reaches your systemReceive the result through payment_result, see SDK-owned buttons; embedded WebView limits in Google Pay in embedded app WebViews
Direct APIYou load the Google Pay JS SDK and obtain the tokenEvery step under "Direct API integration" on this page

All three methods require HTTPS and Google Pay enabled on your Onerway merchant account. Browser and device support follows the Google Pay Web documentation; for sandbox testing, join the test card group with a Google account, see Test cards.

Setup

Before integrating through the Direct API, decide how token authentication methods are handled, who decrypts the token, and where the merchant identifier comes from.

Token authentication method

authMethod is determined by the status of the customer's card on the Google side and you cannot choose it; Onerway requires allowedAuthMethods to declare both values below, accepting only one is not supported:

  • CRYPTOGRAM_3DS: a card the customer has tokenized on the device; the token carries a dynamic cryptogram and 3DS credentials and can be authorized directly.
  • PAN_ONLY: a card saved to the Google account but not tokenized on a device; the token carries no 3DS credentials, so the CVC must be collected before it can be charged, see "Two paths for PAN_ONLY tokens".

Both values occur in real traffic, and not declaring PAN_ONLY means you cannot charge those customers. PAN_ONLY does not mean the card number reaches you: with Onerway decryption the token is encrypted with the Onerway key and the card number never enters your systems, and on the standard path the CVC is collected on an Onerway-hosted page, so no PCI DSS compliance is required. PCI DSS applies only if you choose merchant decryption or collect the CVC yourself.

Decryption mode

ModeFront-end tokenizationSubmitted to OnerwayPrerequisite
Onerway decryption (recommended)PAYMENT_GATEWAY, with the gateway parameters from List available payment methodstokenInfo, token passed through unchangedNone
Merchant decryptionDIRECT, ECv2 with the public key registered in your own Google Pay & Wallet ConsoleOmit tokenInfo; put the decrypted result in cardInfoPCI DSS required

For merchant decryption, map the decrypted result into cardInfo as follows:

Decrypted Google fieldcardInfo field
pancardNumber
expirationMonth, expirationYearmonth, year
authMethodwallet.googlePay.authMethod
cryptogram, eciIndicator (CRYPTOGRAM_3DS only)cryptogram, eci

Merchant identifier

Google requires merchantInfo.merchantId when environment is PRODUCTION (optional in TEST). Its value depends on how your domain is registered; choose one:

  • Onerway registers your domain under its Google Pay & Wallet Console profile: use the merchantId returned by List available payment methods.
  • You register your own Google Pay & Wallet Console profile and domain: use your own merchant identifier. Merchant decryption requires this option.

Confirm with Onerway technical support which account you will use, then complete website registration before going live.

Website registration before going live

This applies only to Direct API integrations; Checkout and the Web SDK use Onerway's Google Pay integration and need no website registration.

Register your website and obtain Google's approval before accepting production payments; a successful sandbox test does not replace it. Follow Google's Publish your integration guide for the Google Pay account you use:

Google Pay accountWho submits the website for approvalWhat you need to do
Your own accountYouAdd the website in your Google Pay & Wallet Console with its domain and integration screenshots, then submit it for approval.
Onerway's accountOnerwaySend the domain and the five screenshots below to Onerway technical support; Onerway submits the website and notifies you of the result.

The domain is the website that calls the Google Pay API. The account determines only the merchantInfo.merchantId to use: your own account does not require merchant decryption, and when Onerway decrypts the token, gatewayName and gatewayMerchantId still come from List available payment methods.

Five screenshots for Onerway registration

Provide one screenshot for each stage of your purchase flow:

ScreenshotWhat it must show
Item selectionThe customer browsing an item or service.
Pre-purchase screenThe customer ready to make a purchase.
Payment method screenThe customer selecting Google Pay as the payment method.
Google Pay API payment screenThe Google Pay payment sheet showing the customer's saved payment information.
Post-purchase screenThe page shown after a successful purchase.

If Android blocks screenshots of the Google Pay payment sheet, photograph the screen with another device; for this item only, an image of an error message is also accepted.

Switch to production after approval

After Google approves the website, set the merchantInfo.merchantId of the registering account, create the PaymentsClient with environment=PRODUCTION, and create transactions with your Onerway production API base URL and credentials.

Direct API integration

Fetch the Onerway configuration

On your server, call List available payment methods, take the paymentMethod=GooglePay record, and return the configuration to the page. Cache it and refresh it when it changes.

Returned fieldGoogle Pay parameter
gatewayNamegateway in tokenizationSpecification
gatewayMerchantIdgatewayMerchantId in tokenizationSpecification
subCardTypesallowedCardNetworks, already upper case as Google expects; pass through unchanged
merchantIdmerchantInfo.merchantId (see "Merchant identifier")
countryCodetransactionInfo.countryCode

Initialize and show the button

Load the Google Pay JS SDK, create a PaymentsClient, check availability with isReadyToPay(), and render the official button with createButton() once it passes.

<script async src="https://pay.google.com/gp/p/js/pay.js" onload="onGooglePayLoaded()"></script>
const paymentsClient = new google.payments.api.PaymentsClient({ environment: 'TEST' }) // 'PRODUCTION' when live

Start the payment

On click, build the PaymentDataRequest, call loadPaymentData(), and take the token from tokenizationData.token in the result to your server. The request needs at least apiVersion: 2, allowedPaymentMethods with the tokenization parameters, transactionInfo with totalPriceStatus as FINAL plus totalPrice, currencyCode, and countryCode, and merchantInfo. Enable emailRequired or shippingAddressRequired if you want the Google Pay sheet to collect contact details.

Create the transaction

On your server, call Create direct transaction with productType=CARD, subProductType=DIRECT, and txnType=SALE, submitting tokenInfo or cardInfo according to the decryption mode; complete requests are shown in the "Onerway-decrypted Google Pay payment" and "Merchant-decrypted Google Pay CRYPTOGRAM_3DS payment" examples of that endpoint.

Handle the synchronous response

A respCode other than 20000 is a failure; data.status=S is success; data.status=R with actionType=RedirectURL means the token is PAN_ONLY and the CVC is still needed: redirect the customer to redirectUrl (an Onerway-hosted page) immediately, and the customer returns to txnOrderMsg.returnUrl after entering it. In that response transactionId is null, so associate the order by merchantTxnId. Any other status is processing; wait for the webhook.

Confirm the final result

The final state is determined by the payment result webhook, which carries walletTypeName=GooglePay for wallet transactions; check that the amount and currency in the webhook match your order. Signature verification, acknowledgement, and deduplication are covered in Webhooks.

Two paths for PAN_ONLY tokens

AspectStandard pathYou collect the CVC
CVC collectionOnerway-hosted pageYour own input field
Customer experienceOne redirect and returnNo redirect
ImplementationHandle the status=R redirect onlyOne extra check call plus a CVC input
CVC security responsibilityOnerwayYou: never store or log it, transmit over HTTPS, clear it after use

Neither path needs extra enablement.

When you collect the CVC yourself:

  • After obtaining the token, call Check Google Pay PAN_ONLY token first.
  • When checkResult=false, collect the CVC from the customer and create the direct transaction with the same tokenInfo and the CVC in cardInfo.cvv. For a PAN_ONLY token submitted without cardInfo.cvv, the transaction response contains data.status=R and data.redirectUrl; redirect the customer to data.redirectUrl to enter the CVC on the Onerway-hosted page. This applies whether or not you called the check endpoint before creating the transaction.
  • When checkResult=true, create the direct transaction with the same tokenInfo; cardInfo is not required.
  • The check and the transaction must use the same token and the same merchantTxnId; fall back to the standard path if the check call fails.
  • Validate the CVC length in real time (3 digits for most card networks, 4 for American Express), display it as a password field, and tell the customer why it is needed.

Front-end example

Fill in the configuration from your server; processPayment hands the token to your server.

<div id="container"></div>
<script>
  // Configuration from the GooglePay record returned by List available payment methods on your server
  const onerwayConfig = {
    gateway: '<gatewayName>',
    gatewayMerchantId: '<gatewayMerchantId>',
    allowedCardNetworks: ['MASTERCARD', 'VISA'],
    merchantId: '<merchantId>',
    countryCode: 'US'
  }

  const baseRequest = { apiVersion: 2, apiVersionMinor: 0 }
  const baseCardPaymentMethod = {
    type: 'CARD',
    parameters: { allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'], allowedCardNetworks: onerwayConfig.allowedCardNetworks }
  }
  const cardPaymentMethod = {
    ...baseCardPaymentMethod,
    tokenizationSpecification: {
      type: 'PAYMENT_GATEWAY',
      parameters: { gateway: onerwayConfig.gateway, gatewayMerchantId: onerwayConfig.gatewayMerchantId }
    }
  }

  let paymentsClient = null
  function getPaymentsClient() {
    if (!paymentsClient) {
      paymentsClient = new google.payments.api.PaymentsClient({ environment: 'TEST' }) // 'PRODUCTION' when live
    }
    return paymentsClient
  }

  function getPaymentDataRequest() {
    return {
      ...baseRequest,
      allowedPaymentMethods: [cardPaymentMethod],
      transactionInfo: { countryCode: onerwayConfig.countryCode, currencyCode: 'USD', totalPriceStatus: 'FINAL', totalPrice: '99.99' },
      merchantInfo: { merchantId: onerwayConfig.merchantId, merchantName: 'Example Store' }
    }
  }

  function onGooglePayLoaded() {
    getPaymentsClient()
      .isReadyToPay({ ...baseRequest, allowedPaymentMethods: [baseCardPaymentMethod] })
      .then((res) => {
        if (!res.result) return
        const button = getPaymentsClient().createButton({ onClick: onButtonClicked, allowedPaymentMethods: [baseCardPaymentMethod] })
        document.getElementById('container').appendChild(button)
      })
  }

  function onButtonClicked() {
    getPaymentsClient()
      .loadPaymentData(getPaymentDataRequest())
      .then(processPayment)
      .catch(() => {
        // The customer closed the Google Pay sheet or the payment failed; restore the page
      })
  }

  async function processPayment(paymentData) {
    // Never log or store the token
    const paymentToken = paymentData.paymentMethodData.tokenizationData.token
    // Server calls Create direct transaction (tokenInfo.provider=GooglePay), maps a respCode other than 20000 to status 'F', and returns { status, redirectUrl }
    const res = await fetch('/api/google-pay/process-payment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ paymentToken })
    }).then(r => r.json())

    if (res.status === 'R' && res.redirectUrl) {
      window.location.href = res.redirectUrl // PAN_ONLY: redirect to the Onerway-hosted page to collect the CVC; the final state comes from the webhook
    } else if (res.status === 'S') {
      // Synchronous success; the payment result webhook remains the final source of truth
    } else if (res.status === 'F') {
      // Failed; ask the customer to choose another payment method
    } else {
      // Processing; wait for the payment result webhook
    }
  }
</script>
<script async src="https://pay.google.com/gp/p/js/pay.js" onload="onGooglePayLoaded()"></script>

Google resources: Web integration guide, interactive demos, brand guidelines.

Wallet subscriptions

Google Pay can be used for subscriptions: submit subProductType=SUBSCRIBE with subscription on the initial subscription; both selfExecute=1 (managed by Onerway) and selfExecute=2 (you initiate each billing) are supported. On Checkout, lock to Google Pay with lpmsInfo.lpmsType=GooglePay; on the Direct API, submit the encrypted wallet token in tokenInfo to create the initial subscription. After the initial subscription succeeds, the subscription payment webhook returns contractId and the subscription tokenId; renewals and plan changes then work the same as card subscriptions, see Subscription payments.

Differences from card subscriptions: the encrypted wallet token is single-use and cannot be saved for reuse, so the only billing credential during the subscription is the subscription token; wallet subscriptions produce no saved payment method result webhook and return no card token.

Common issues

SymptomCommon causesWhat to do
The button does not appearpay.js not loaded, not HTTPS, no usable card in the account, or an embedded app WebView that does not meet the requirementsCheck the isReadyToPay() result; for WebViews see Web SDK integration
Configuration cannot be fetchedYour server did not return gatewayName, gatewayMerchantId, or subCardTypesCheck the List available payment methods call and filtering
The production sheet reports an unverified merchantmerchantInfo.merchantId missing or not matching the domain registration approachConfirm the source of the value under "Merchant identifier"
PAN_ONLY not handledCreate direct transaction returned redirectUrl but the page did not redirectRedirect as soon as redirectUrl is returned, or switch to collecting the CVC yourself

Go-live checklist

  • Direct API only: website registration is complete and approved by Google.
  • The token is never decrypted on the client and never logged or stored.
  • Both the PAN_ONLY redirect path and the CRYPTOGRAM_3DS direct success path have been tested with real cards.
  • If you collect the CVC yourself, the fallback for a failed check call has been tested.
  • Webhook signature verification, deduplication, and amount checks are in place.