Google Pay
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 method | Button and token | What you do |
|---|---|---|
| Checkout | The checkout page renders the button; the token never reaches your system | Submit productType=ALL, or lpmsInfo.lpmsType=GooglePay to lock to Google Pay |
| Web SDK | The SDK renders the button on your page, appearance in Configure wallet buttons; the token never reaches your system | Receive the result through payment_result, see SDK-owned buttons; embedded WebView limits in Google Pay in embedded app WebViews |
| Direct API | You load the Google Pay JS SDK and obtain the token | Every 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
| Mode | Front-end tokenization | Submitted to Onerway | Prerequisite |
|---|---|---|---|
| Onerway decryption (recommended) | PAYMENT_GATEWAY, with the gateway parameters from List available payment methods | tokenInfo, token passed through unchanged | None |
| Merchant decryption | DIRECT, ECv2 with the public key registered in your own Google Pay & Wallet Console | Omit tokenInfo; put the decrypted result in cardInfo | PCI DSS required |
For merchant decryption, map the decrypted result into cardInfo as follows:
| Decrypted Google field | cardInfo field |
|---|---|
pan | cardNumber |
expirationMonth, expirationYear | month, year |
authMethod | wallet.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
merchantIdreturned 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 account | Who submits the website for approval | What you need to do |
|---|---|---|
| Your own account | You | Add the website in your Google Pay & Wallet Console with its domain and integration screenshots, then submit it for approval. |
| Onerway's account | Onerway | Send 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:
| Screenshot | What it must show |
|---|---|
| Item selection | The customer browsing an item or service. |
| Pre-purchase screen | The customer ready to make a purchase. |
| Payment method screen | The customer selecting Google Pay as the payment method. |
| Google Pay API payment screen | The Google Pay payment sheet showing the customer's saved payment information. |
| Post-purchase screen | The 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 field | Google Pay parameter |
|---|---|
gatewayName | gateway in tokenizationSpecification |
gatewayMerchantId | gatewayMerchantId in tokenizationSpecification |
subCardTypes | allowedCardNetworks, already upper case as Google expects; pass through unchanged |
merchantId | merchantInfo.merchantId (see "Merchant identifier") |
countryCode | transactionInfo.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
| Aspect | Standard path | You collect the CVC |
|---|---|---|
| CVC collection | Onerway-hosted page | Your own input field |
| Customer experience | One redirect and return | No redirect |
| Implementation | Handle the status=R redirect only | One extra check call plus a CVC input |
| CVC security responsibility | Onerway | You: 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 sametokenInfoand the CVC incardInfo.cvv. For aPAN_ONLYtoken submitted withoutcardInfo.cvv, the transaction response containsdata.status=Randdata.redirectUrl; redirect the customer todata.redirectUrlto 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 sametokenInfo;cardInfois 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
| Symptom | Common causes | What to do |
|---|---|---|
| The button does not appear | pay.js not loaded, not HTTPS, no usable card in the account, or an embedded app WebView that does not meet the requirements | Check the isReadyToPay() result; for WebViews see Web SDK integration |
| Configuration cannot be fetched | Your server did not return gatewayName, gatewayMerchantId, or subCardTypes | Check the List available payment methods call and filtering |
| The production sheet reports an unverified merchant | merchantInfo.merchantId missing or not matching the domain registration approach | Confirm the source of the value under "Merchant identifier" |
| PAN_ONLY not handled | Create direct transaction returned redirectUrl but the page did not redirect | Redirect 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_ONLYredirect path and theCRYPTOGRAM_3DSdirect 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.
Apple Pay
How Apple Pay differs across Checkout, Web SDK, and Direct API, domain verification and account setup, the Direct API session flow and token submission, wallet subscriptions, and common issues.
Local payment methods
How to find which methods Onerway supports and which are available for an order, the differences across integration methods, the three customer actions and delayed settlement, method-specific parameters, subscription-capable methods, and the extra requirements of some regional methods.