Markdown

Google Pay

Fetch Google Pay configuration from the gateway, run the Google Pay JS session on your payment page, and authorize the resulting token with CCAUTHCAP.

Google Pay overview

This section covers sending credit card transactions to the gateway using Google Pay.

To accept Google Pay, the web pages that host your payment forms must have their domains registered. The Processor and Merchant Account you use must also support Google Pay; contact your gateway support representative for more information.

For more information on Google Pay itself, see Google's own documentation: an overview of Google Pay, the Google Pay Integration Checklist, and the Google Pay Branding Guidelines, along with Google's list of payment methods that support Google Pay (your allowedCardNetworks is determined by your merchant account configuration), Google's list of countries/regions where Google Pay is available (the gateway supports the currencies enabled by your merchant account configuration), and Google's list of supported browsers.

Real cards required for production testing

Test cards will not work when testing Google Pay in a production environment. A real PAN must be used.

Integration flow

These are the steps to integrate Google Pay with the gateway:

  1. Fetch your Google Pay configuration data from the gateway.
  2. Add the Google Pay library to your payment page.
  3. Customize the Google Pay button.
  4. Handle the Google Pay loaded event.
  5. Present the Google Pay button.
  6. Handle the Google Pay button click.
  7. Handle payment authorization.
  8. Submit the authorized payment data.

Each step is discussed below with example code. The example code is illustrative only and does not represent code that can be used as-is in a production environment.

Fetching your Google Pay configuration

You need configuration data from the gateway to set up the Google Pay session after the customer clicks the Google Pay button.

POSThttps://api.inoviopay.com/payment/googlepay.cfm

Requests must be made in JSON format.

Request parameters

Field Name Description
REQ_USERNAME Required API credential username.
REQ_PASSWORD Required API credential password.
DOMAIN_NAME Required Domain name where the payment page is hosted/served from.
CLIENT_ID Required Client ID.
REQUEST_ACTION Required GOOGLEPAYCONFIG. Used to instruct the endpoint to provide the proper Google Pay configuration for your unique information.

All parameters are required.

Sample body request

{
  "request_login": "googlepayClient@Inovio.com",
  "request_password": "Test123",
  "request_action": "GOOGLEPAYCONFIG",
  "domain_name": "paymentpagedomain.com",
  "client_id": "100"
}

Sample response

{
    "GOOGLEPAY_CLI_CONF_ID": 1,
    "REQ_ID": 2744,
    "CLIENT_ID": 100,
    "DOMAIN_LIST": [
        {
            "DOMAIN_NAME": "paymentpagedomain.com",
            "DOMAIN_STATUS": "ACTIVE"
        }
    ],
    "hostConfig": {
        "merchantId": "BC...JW",
        "environment": "TEST",
        "merchantName": "Inovio",
        "gatewayId": "inoviopay",
        "gatewayMerchantId": "string-string"
    }
}

Provide this response on your payment page as the merchantConfig parameter.

Adding the Google Pay library

Import the Google Pay JavaScript library into your payment page, and add an empty <div> titled gpay-container. This div is the placeholder where the Google Pay button appears; you can place it anywhere on your page.

<!DOCTYPE html>
<html lang="en">
 <script>
   function onGPayApiLoaded() {
     googlePayHandler.initialize({
       gpayButtonContainerId: 'gpay-container' // The ID of the div where the button should appear
     });
   }
 </script>
  <body>
     <div id="gpay-container"></div>
     <script type="text/javascript" src="main.js"></script>
     <script async src="https://pay.google.com/gp/p/js/pay.js" onload="onGPayApiLoaded()"></script>
  </body>
</html>

The <div id="gpay-container"></div> is your designated spot for the button. The pay.js script tag asynchronously loads the Google Pay library. The onload="onGooglePayLoaded()" attribute ensures your onGooglePayLoaded() function (which checks whether Google Pay is ready) runs as soon as the library finishes loading.

Customizing the Google Pay button

The Google Pay button should fit your website's design and user experience; consult Google's documentation for how to achieve this. After the Google Pay API is loaded and ready, your site can display the button. It is dynamically generated by the Google Pay library and placed inside the gpay-container div.

const GPAY_BUTTON_CONTAINER_ID = 'gpay-container';
function renderGooglePayButton() {
  const button = getGooglePaymentsClient().createButton({
    buttonColor: 'default',
    buttonType: 'buy',
    buttonRadius: 4,
    buttonLocale: 'en',
    onClick: onGooglePaymentButtonClicked,
    allowedPaymentMethods: baseGooglePayRequest.allowedPaymentMethods,
  });
  document.getElementById(GPAY_BUTTON_CONTAINER_ID).appendChild(button);
}

The createButton() library method takes a ButtonOptions configuration argument that defines how the button looks and behaves:

  • GPAY_BUTTON_CONTAINER_ID: constant holding the ID (gpay-container) of the HTML element where the button should appear.
  • renderGooglePayButton(): function responsible for creating and adding the button.
  • getGooglePaymentsClient().createButton({...}): uses the Google Pay client to generate the button. The ButtonOptions object allows customization:
  • buttonColor: choose the appearance (default, black, white).
  • buttonType: defines the text on the button (for example "Buy/Checkout with Google Pay").
  • buttonRadius: adjusts the roundness of the button's corners.
  • buttonLocale: sets the language for the button's text.
  • onClick: onGooglePaymentButtonClicked: calls your onGooglePaymentButtonClicked function (which initiates the payment process) whenever a customer clicks the button.
  • allowedPaymentMethods: ensures the button only appears if there are payment methods available that match what you've configured in baseGooglePayRequest.
  • document.getElementById(...).appendChild(button): inserts the button Google Pay created directly into the div on your webpage, making it visible to the user.

Handling the Google Pay loaded event

The onGooglePayLoaded() function is called when the Google Pay API script has finished loading. It is the handshake with the Google Pay service, ensuring everything is in order before you present the payment option to your customers.

function onGooglePayLoaded() {
  const req = deepCopy(baseGooglePayRequest);
  getGooglePaymentsClient()
    .isReadyToPay(req)
    .then(function (res) {
       if (res.result) {
         renderGooglePayButton();
       } else {
         console.log('Google Pay is not ready for this user.');
       }
    })
    .catch(console.error);
}

Configuring Google Pay

The baseGooglePayRequest object defines the fundamental configuration for all Google Pay requests.

const baseGooglePayRequest = {
   apiVersion: 2,
   apiVersionMinor: 0,
   allowedPaymentMethods: [
      {
         type: 'CARD',
         parameters: {
            allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
            allowedCardNetworks: ['AMEX', 'DISCOVER', 'MASTERCARD', 'VISA'],
         },
         tokenizationSpecification: {
            type: "PAYMENT_GATEWAY",
            parameters: {
              "gateway": "inoviopay",
              "gatewayMerchantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
            }
         },
      },
   ],
   merchantInfo,
};
Object.freeze(baseGooglePayRequest);
let paymentsClient = null;
function getGooglePaymentsClient() {
   if (paymentsClient === null) {
      paymentsClient = new google.payments.api.PaymentsClient({
         environment: 'TEST', // Environment configuration
         merchantInfo,
         paymentDataCallbacks: {
            onPaymentAuthorized: onPaymentAuthorized,
            onPaymentDataChanged: onPaymentDataChanged,
         },
      });
   }
   return paymentsClient;
}

Key properties that shape the Google Pay experience:

  • apiVersion and apiVersionMinor: tell Google Pay which version of the Google Pay API you are using.
  • allowedPaymentMethods: array declaring what types of payments you accept.
  • parameters (within the CARD type):
    • allowedAuthMethods: defines the authentication methods your integration supports:
    • PAN_ONLY: used for cards saved directly to a user's Google account. Google Pay returns the actual card number. To use 3D Secure with PAN_ONLY, submit your third party 3-D Secure details with the authorization; the gateway will not prevent a transaction from being sent to the processor without 3DS on the transaction request.
    • CRYPTOGRAM_3DS: used for cards tokenized via the Google Wallet app. Instead of the real card number, a device-specific token is used. A 3-D Secure cryptogram is generated on the user's device, providing stronger security and often shifting liability for fraud to the card issuer. Inovio recommends using this allowedAuthMethods value only.
    • allowedCardNetworks: lists all the major card networks your Merchant Account is set up to accept (American Express, Discover, Mastercard, Visa, and/or more). See Google's official Google Pay documentation for details.
  • tokenizationSpecification: configuration for how payment credentials are secured and sent to your payment processor.
    • type: "PAYMENT_GATEWAY": indicates that the payment gateway handles tokenization on your behalf.
    • parameters: gateway-specific details essential for secure processing, provided to you when you request your configuration data from the gateway:
    • gateway: the name of your payment gateway (for example inoviopay).
    • gatewayMerchantId: your unique ID provided by the gateway.
  • Object.freeze(baseGooglePayRequest): prevents accidental changes to your base Google Pay configuration after it is set.
  • paymentsClient starts as null; getGooglePaymentsClient() uses lazy initialization, creating the PaymentsClient instance only when needed.
  • environment: 'TEST' is for development and debugging; change to 'PRODUCTION' when you're ready to go live.
  • paymentDataCallbacks: functions to handle events during the Google Pay flow:
  • onPaymentAuthorized: called after the user has successfully authorized a payment. This is where you send the payment data to the payment service provider for processing.
  • onPaymentDataChanged: fires if the user changes their payment data (such as selecting a different shipping address or payment method) within the Google Pay sheet, letting you dynamically update the order total or shipping options.

Handling the Google Pay button click

When a user clicks your Google Pay button, onGooglePaymentButtonClicked() gathers the specifics of the current transaction and launches the Google Pay payment window.

// @namespace googlePayHandler
// @description A self-contained handler for a professional and secure Google Pay
// integration. This script manages fetching configuration from a secure backend,
// setting up the Google Pay client, and handling the entire payment lifecycle.
const googlePayHandler = {
  // Default settings can be overridden by the customer during initialization.
  config: {
    gpayButtonContainerId: 'gpay-container',
    currencyCode: 'USD',
    countryCode: 'US',
    environment: 'TEST', // Should be 'PRODUCTION' for live transactions
  },
  // --- Internal State ---
  paymentsClient: null,
  merchantConfig: null,
  // CRITICAL: Fetches the merchant configuration from the CUSTOMER'S backend.
  // This is a vital security measure. API credentials should NEVER be exposed in
  // client-side code.
  // Your customer must implement a server endpoint that securely communicates with
  // your API.
  // @returns {Promise<Object|null>} A promise that resolves with the merchant
  // configuration or null on failure.
  async fetchMerchantConfigFromServer() {
     // --- CUSTOMER ACTION REQUIRED ---
     // This URL must point to an endpoint on YOUR CUSTOMER'S server.
     // Their server is responsible for making the secure, server-to-server call to the
     // Inovio API.
     const customerBackendUrl = 'https://api.customer-website.com/get-payment-config';
     try {
       const response = await fetch(customerBackendUrl);
       if (!response.ok) {
         throw new Error(`Network response was not ok: ${response.statusText}`);
       }
       const configData = await response.json();
       console.log("Successfully fetched merchant configuration.");
       return configData;
     } catch (error) {
       console.error("Fatal Error: Could not retrieve merchant configuration from the server.", error);
       // Optional: Display a user-friendly error message in the UI.
       // e.g., document.getElementById(this.config.gpayButtonContainerId).innerText =
       // "Payment system unavailable.";
       return null;
     }
  },
  // Initializes the Google Pay client if it doesn't already exist.
  // @returns {google.payments.api.PaymentsClient}
  getGooglePaymentsClient() {
     if (this.paymentsClient === null) {
       if (!this.merchantConfig) {
         throw new Error("Cannot initialize Google Payments client without merchant configuration.");
       }
       this.paymentsClient = new google.payments.api.PaymentsClient({
         environment: this.config.environment,
         merchantInfo: {
              merchantId: this.merchantConfig.HOST_CONFIG.merchantId,
              // Customer will set their own display name
              merchantName: this.merchantConfig.HOST_CONFIG.merchantName || 'Sample Merchant',
         },
         paymentDataCallbacks: {
            onPaymentAuthorized: this.onPaymentAuthorized,
            onPaymentDataChanged: this.onPaymentDataChanged,
         },
       });
     }
     return this.paymentsClient;
  },
  // Main entry point. Initializes the Google Pay flow.
  // @param {Object} [userConfig={}] - Customer-specific configuration to override the
  // defaults.
  async initialize(userConfig = {}) {
     // 1. Merges customer's configuration with defaults.
     this.config = { ...this.config, ...userConfig };
     // 2. Securely fetches the configuration from the customer's backend.
     this.merchantConfig = await this.fetchMerchantConfigFromServer();
     if (!this.merchantConfig) {
       console.error("Google Pay initialization failed: Merchant configuration is missing or could not be fetched.");
       return;
     }
     const isReadyToPayRequest = this.createBaseRequest();
     this.getGooglePaymentsClient()
       .isReadyToPay(isReadyToPayRequest)
       .then((isReadyToPayRequest) => {
          if (isReadyToPayRequest.result) {
            this.renderGooglePayButton();
          } else {
            console.log('Google Pay is not ready for this user.');
          }
       })
       .catch(console.error);
  },
  // Creates and appends the Google Pay button to the configured container.
  renderGooglePayButton() {
     const container = document.getElementById(this.config.gpayButtonContainerId);
     if (!container) {
          console.error(`Google Pay button container with ID "${this.config.gpayButtonContainerId}" was not found in the DOM.`);
          return;
     }
     // Clears any previous content (e.g. error messages)
     container.innerHTML = '';
     const button = this.getGooglePaymentsClient().createButton({
       onClick: this.onGooglePaymentButtonClicked.bind(this),
       allowedPaymentMethods: this.createBaseRequest().allowedPaymentMethods,
     });
     container.appendChild(button);
  },
  // Creates the base payment request object required by the Google Pay API.
  // @returns {Object} The Google Pay base request object.
  createBaseRequest() {
     return {
       apiVersion: 2,
       apiVersionMinor: 0,
       allowedPaymentMethods: [{
          type: 'CARD',
          parameters: {
            allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
            allowedCardNetworks: ['AMEX', 'DISCOVER', 'INTERAC', 'JCB', 'MASTERCARD', 'VISA'],
          },
          tokenizationSpecification: {
             type: 'PAYMENT_GATEWAY',
             parameters: {
                gateway: this.merchantConfig.HOST_CONFIG.gatewayId,
                gatewayMerchantId: this.merchantConfig.MERCH_IDENTIFIER,
                // These values should come from your secure config fetch
             },
          },
       }],
     };
  },
  // Handles the click event from the Google Pay button.
  onGooglePaymentButtonClicked() {
     const paymentDataRequest = {
        ...this.createBaseRequest(),
        transactionInfo: {
           countryCode: this.config.countryCode,
           currencyCode: this.config.currencyCode,
           totalPriceStatus: 'FINAL',
           totalPrice: '10.00',
        },
        merchantInfo: {
           merchantId: this.merchantConfig.MERCH_IDENTIFIER,
           merchantName: this.merchantConfig.MERCHANT_NAME || 'Sample Merchant'
        },
        // The callbackIntents must match the callbacks provided in
        // getGooglePaymentsClient(). We provided onPaymentAuthorized and
        // onPaymentDataChanged. To handle dynamic shipping, you would add
        // 'SHIPPING_ADDRESS' and 'SHIPPING_OPTION' and then build out the
        // logic in the onPaymentDataChanged callback.
        callbackIntents: ['PAYMENT_AUTHORIZATION'],
     };
     console.log('Requesting payment data...', paymentDataRequest);
     this.getGooglePaymentsClient()
        .loadPaymentData(paymentDataRequest)
        .catch(err => console.error("loadPaymentData error:", err)); // Catches user cancellation or other errors.
  },
  // Callback for when payment is successfully authorized by the user.
  // @param {Object} paymentData - The authorized payment data from Google, including
  // the token.
  // @returns {Promise<Object>} A promise resolving with the final transaction
  // result.
  onPaymentAuthorized(paymentData) {
     return new Promise((resolve) => {
        console.log('Payment authorized. Response from Google:', paymentData);
        const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
        // --- CUSTOMER ACTION REQUIRED ---
        // 1. Send this `paymentToken` to your server. Never do this from the client
        // side.
        // 2. On your server, use this token to make the final "charge" or
        // "auth/capture" call to the Payment Gateway API. NEVER do this from the client side.
        // 3. Based on the response from the Payment Gateway, resolve with the final
        // state.
        console.log("Action required: Send this payment token to your server for processing:", paymentToken);
        // Fetch your server here.
        resolve({ transactionState: 'SUCCESS' });
        // Example of resolving with an error if the Payment Gateway declines the
        // transaction:
        /*
        resolve({
           transactionState: 'ERROR',
           error: {
              intent: 'PAYMENT_AUTHORIZATION',
              message: 'Your payment was declined by the issuer. Please try another card.',
              reason: 'PAYMENT_DATA_INVALID',
           },
        });
        */
     });
  },
}
// Optional callback for when payment data changes (e.g., shipping address or
// options).
// @param {Object} intermediatePaymentData
// @returns {Promise<Object>}
function onPaymentDataChanged(intermediatePaymentData) {
   return new Promise((resolve) => {
     console.log('Intermediate payment data changed:', intermediatePaymentData);
     // This is where you would implement dynamic updates, such as recalculating
     // shipping costs or taxes based on the user's selected address.
     // For this example, we do nothing and resolve an empty object.
     resolve({});
   });
}

The googlePayHandler is designed to make Google Pay work smoothly and securely:

  • Default settings: currency (USD), country (US), and TEST mode (use PRODUCTION for live transactions).
  • Getting merchant information: the system gets setup information from your store's backend server. Never put sensitive payment details directly on the website itself; the server talks securely to the gateway. If it can't get this information, Google Pay can't start.
  • Setting up Google Pay: once googlePayHandler has the store's information, it sets up the connection to Google Pay.
  • Checking readiness: the system checks whether the customer's device and browser are ready to use Google Pay, showing the button if so and hiding it otherwise.
  • Showing the button: if everything is ready, googlePayHandler places the Google Pay button on the page where you told it to appear.
  • Preparing the payment request: clicking the Google Pay button creates a detailed request for the payment, per Configuring Google Pay.
  • Opening the Google Pay window: this request is sent to Google Pay, which opens the payment window.
  • Getting a secure token: on successful payment, the system receives a paymentToken, a highly secure encrypted representation of the payment.
  • Security step: this paymentToken must never be handled directly on the browser or device beyond receiving it; it is sent immediately to the store's secure backend server, which is the only place that should process this Google Pay token to complete the payment with Inovio.
  • Finalizing the payment: the store's server uses paymentToken to make the final "charge" or "authorize" transaction with the gateway.
  • Handling changes (optional): if the customer changes their shipping address within Google Pay, the system can automatically update shipping costs or taxes.

Payment authorization

onPaymentAuthorized() is called automatically after the user has successfully gone through the Google Pay sheet and approved the payment. This is where you take the secure payment information and send it to your payment processor.

function onPaymentAuthorized(paymentData) {
  return new Promise(function (resolve, reject) {
    // Write the data to console for debugging
    console.log('onPaymentAuthorized', paymentData);
    // --- CUSTOMER ACTION REQUIRED ---
    // 1. Send this `paymentToken` to your server.
    // 2. On your server, use this token to make the final "charge" or
    // "auth/capture" call to the Inovio gateway API. NEVER do this from the client side.
    // 3. Based on the response from the Inovio gateway, resolve with the final
    // state.
    const paymentAuthorizationResult = { transactionState: 'SUCCESS' };
    // Example of resolving with an error if your gateway declines the payment:
    /**
    const paymentAuthorizationResult ={
              transactionState: 'ERROR',
              error: {
                 intent: 'PAYMENT_AUTHORIZATION',
                 message: 'Insufficient funds',
                 reason: 'PAYMENT_DATA_INVALID',
              },
           };
    */
    resolve(paymentAuthorizationResult);
  });
}

When this function is called, Google Pay hands you the paymentData object. Inside it is the secure Google payment token, at paymentData.paymentMethodData.tokenizationData.token. This token represents the customer's payment method without exposing their actual card details.

The critical backend step, though commented out in the example above, is sending this Google payment token to your own secure server. Your server is then responsible for sending the Google Pay token to the gateway to authorize and capture the funds, and receiving the processing result from the gateway.

onPaymentAuthorized(paymentData) returns a Promise, letting you perform asynchronous operations and then resolve with the final paymentAuthorizationResult when you have it. In essence, onPaymentAuthorized() is the bridge between the customer approving the payment in Google Pay and your system charging their card through your payment processor.

Submitting authorized payment data

Once Google Pay returns the authorized payment token, send it to the gateway as a normal CCAUTHCAP request, passing the token in PMT_WALLET_CRYPTOGRAM:

https://api.inoviopay.com/payment/pmt_service.cfm?request_action=CCAUTHCAP&li_count_1=1&li_prod_id_1=111&li_value_1=49.95&req_username=GATEWAY_USER&req_password=GATEWAY_PASS&site_id=11111&request_response_format=JSON&request_api_version=4.14&request_currency=USD&PMT_WALLET=googlepay&PMT_WALLET_CRYPTOGRAM=xxxxxxx

Important requirements for Google Pay authorization requests

You must not include any of the following parameters; doing so will cause the gateway to reject the request:

  • PMT_NUMB
  • PMT_KEY
  • PMT_EXPIRY
  • TOKEN_GUID
  • PMT_ID
  • PMT_LAST4
  • PMT_ID_XTL
  • BILL_ADDR_STATE
  • BILL_ADDR_ZIP
  • BILL_ADDR_COUNTRY
  • BILL_ADDR_CITY
  • BILL_ADDR

Other gateway parameters can be included, but they must match the values used in the Google Pay session:

  • li_value_1 must match the value of paymentRequest.total in the merchantConfig data.
  • request_currency must match the value of paymentRequest.currencyCode in the merchantConfig data.
The PDF gives no further Google Pay field table beyond this

Section 22.10.1 of the source spec lists only the excluded-parameter list and the two must-match rules above; it does not provide a separate table of additional required PMT_WALLET_* fields, so none is invented here.

Rebilling and card on file

The gateway response returns a CUST_ID and PMT_ID on a successful Google Pay authorization, the same as it does for normal transactions. To authorize against the generated Google Pay payment record, pass the same CUST_ID and PMT_ID on all subsequent rebills or unscheduled merchant-initiated card-on-file transaction requests.

Not in the SDKs yet

Google Pay is not implemented in any of the four SDKs. A WalletToken variant (walletType: 'applepay' | 'googlepay') is declared in each language's type system, but PaymentMethods only constructs card, token and savedCard in v1, there is no constructor that produces a wallet payment method, so sale()/authorize() cannot be handed a PMT_WALLET_CRYPTOGRAM token today. Send the authorization as a raw HTTP request per the example above, or see the SDKs. Rebilling against the resulting CUST_ID/PMT_ID does work through the SDK once you have them, using the same SavedCard path as Card on File.