Google Pay API for Web 201: Advanced

1. Introduction

This codelab is a continuation of Google Pay API for Web 101: Basics and relies on code written in that codelab. In order to complete this codelab, be sure to complete that one first.

What you'll learn

  • How to customize the Google Pay button
  • How to start the payment process
  • How to acknowledge payment authorization status
  • How to handle shipping address changes
  • How to handle redemption codes

What you'll need

  • A text editor of your choice to edit HTML and JavaScript files.
  • The Google Chrome web browser, or another way to test a local website.
  • For production, you will need a Google Pay merchantId. It only takes a minute to register at Google Pay & Wallet Console so might as well take care of it now.

Follow along using Project IDX

Open this codelab in IDX

2. Button customization

This is a brief overview of the ButtonOptions. Consult the documentation for more detailed explanation

Option

Necessity

Values

onClick

Required

Name of JavaScript event handler

allowedPaymentMethods

Optional

PaymentMethod[]

buttonColor

Optional

default, black, white

buttonLocale

Optional

Two letter ISO 639-1 code.
Supported locales include en, ar, bg, ca, cs, da, de, el, es, et, fi, fr, hr, id, it, ja, ko, ms, nl, no, pl, pt, ru, sk, sl, sr, sv, th, tr, uk, and zh.

buttonRadius

Optional

0 to 100

buttonRootNode

Optional

HTMLDocument or ShadowRoot

buttonSizeMode

Optional

static, fill

buttonType

Optional

book, buy, checkout, donate, order, pay, plain, subscribe

Look for the renderGooglePayButton() method in your main.js file and replace it with the code listed here.

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);
}

Code explanation

  1. The createButton() library method takes a ButtonOptions configuration argument that lets you define how you want the button to look and behave.

3. Payment data callbacks

The payments client provides a mechanism for you to register functions to handle when certain events happen. The first is payment authorization and the second is payment data change.

  1. Find the // todo: paymentDataCallbacks comment in main.js and replace it with this code.
    paymentDataCallbacks: {
      onPaymentAuthorized: onPaymentAuthorized,
      onPaymentDataChanged: onPaymentDataChanged
    },
    
  2. Then, find the Event Handlers section of main.js and append the following code to the end of the section.
    function onPaymentAuthorized(paymentData) {
      // We'll fill this in later
    }
    
    function onPaymentDataChanged(intermediatePaymentData) {
      // We'll fill this in later
    }
    
    
  3. Finally, find // todo: callbackIntents comment within main.js and replace the comment with this code. In this codelab, we are going to implement all 4 of the intents.
    callbackIntents: [
      'PAYMENT_AUTHORIZATION',
      'SHIPPING_ADDRESS',
      'SHIPPING_OPTION',
      'OFFER',
    ],
    shippingAddressRequired: true,
    shippingOptionRequired: true,
    shippingOptionParameters: {
      defaultSelectedOptionId: 'shipping-001',
      shippingOptions: [
        {
          id: 'shipping-001',
          label: '$0.00: Free shipping',
          description: 'Free Shipping delivered in 5 business days.'
        },
        {
          id: 'shipping-002',
          label: '$1.99: Standard shipping',
          description: 'Standard shipping delivered in 3 business days.'
        },
        {
          id: 'shipping-003',
          label: '$1000: Express shipping',
          description: 'Express shipping delivered in 1 business day.'
        },
      ],
    },
    

Code explanation

  1. The PaymentDataCallbacks property has two sub-properties one for a payment authorization callback and the second for a payment data change callback.
  2. If implementing callbacks, onPaymentAuthorized is required. This callback is invoked when the callbackIntents list contains PAYMENT_AUTHORIZATION in the PaymentDataRequest.
  3. onPaymentDataChanged is optional. This callback is invoked when the callbackIntents list contains OFFER, SHIPPING_ADDRESS, or SHIPPING_OPTION in the PaymentDataRequest.
  4. Set the callbackIntents in the PaymentDataRequest to trigger both callbacks for this codelab.

4. Payment authorization

Authorize Payments is used to start the payment process and acknowledge payment authorization status.

Find the onPaymentAuthorized() function in main.js that you've added in the last step and replace it with the following code.

function onPaymentAuthorized(paymentData) {
  return new Promise(function(resolve, reject) {
    // Write the data to console for debugging
    console.log("onPaymentAuthorized", paymentData);

    // Do something here to pass token to your gateway

    // To simulate the payment processing, there is a 70% chance of success
    const paymentAuthorizationResult = (Math.random() > 0.3)
      ? {transactionState: 'SUCCESS'}
      : {
        transactionState: 'ERROR',
        error: {
          intent: 'PAYMENT_AUTHORIZATION',
          message: 'Insufficient funds',
          reason: 'PAYMENT_DATA_INVALID'
        }
      };

    resolve(paymentAuthorizationResult);
  });
}

Code explanation

  1. The onPaymentAuthorized() callback function is invoked with a PaymentData argument and must return a promise. In this example, the function is randomly choosing whether to return success or an error. In your project, you'll use this opportunity to process the transaction with your gateway using the token found in paymentData at paymentData.paymentMethodData.tokenizationData.token.

5. Payment data change

Dynamic Price Updates allows a merchant to dynamically update shipping options and transaction information based on a chosen shipping address. Additionally, you can dynamically update transaction information based on a chosen shipping option.

Find the onPaymentDataChanged() function in main.js that you've added in the last step and replace it with the following code.

function onPaymentDataChanged(intermediatePaymentData) {
  return new Promise(function(resolve, reject) {
    let paymentDataRequestUpdate = {};

    // Write the data to console for debugging
    console.log("onPaymentDataChanged", intermediatePaymentData);

    switch(intermediatePaymentData.callbackTrigger)
    {
      case "INITIALIZE":
        // Handle initialize
        break;
      case "SHIPPING_ADDRESS":
        // Read intermediatePaymentData.transactionInfo
        // Read intermediatePaymentData.shippingAddress
        // Update paymentDataRequestUpdate.newTransactionInfo
        break;
      case "SHIPPING_OPTION":
        // Read intermediatePaymentData.transactionInfo
        // Read intermediatePaymentData.shippingOptionData
        // Update paymentDataRequestUpdate.newTransactionInfo
        // Update paymentDataRequestUpdate.newShippingOptionParameters
        break;
      case "OFFER":
        // Read intermediatePaymentData.offerData
        // Read intermediatePaymentData.transactionInfo
        // Update paymentDataRequestUpdate.newTransactionInfo
        // Update paymentDataRequestUpdate.newOfferInfo
        break;
      default:
        // Update paymentDataRequestUpdate.error
    }

    resolve(paymentDataRequestUpdate);
  });
}

Code explanation

  1. The onPaymentDataChanged() function takes IntermediatePaymentData as an argument. This function is invoked when the shipping address or shipping options is changed in the payment sheet.
  2. The onPaymentDataChanged() function must return a promise that resolves a PaymentDataRequestUpdate object which specifies new transaction info, shipping options and error to update the payment sheet.
  3. redemptionCodes are a set of promotional codes entered into the payment sheet. Includes codes that have already been approved.

6. Conclusion

Congratulations on completing this Codelab! You have learned how to ...

Run the project

Test with Google Chrome

Using the Google Chrome web browser, open index.html using File > Open File... from Chrome's main menu. Chrome will execute main.js when the project is opened this way. Other web browsers might not allow JavaScript execution.

– or –

Test with a local web server

If you have Python installed, run python3 -m http.server from a terminal prompt in the root pay-web-101 folder.

$ cd /your/path/to/pay-web-101
$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

Then, visit your site at http://localhost:8000.

Where to go from here

Additional resources