# Accept cards with Google Pay™

**This feature is coming soon!** The information below describes a feature that is not yet available in production. The API details are subject to change.

Moov allows you to accept card payments with Google Pay. This step by step guide covers how you can start accepting Google Pay on the web using the open standard Payment Request API.

In addition to being a fast and easy way to accept payments, Google Pay offers strong privacy and security. In this guide, we'll direct you to Google's guidelines, and bring you through a step by step process of adding a functional Google Pay button.

## [Prerequisites](#prerequisites)

Before getting started, make sure your website follows Google's guidelines, and that your server is set up accordingly.

- [Google Pay overview](https://developers.google.com/pay/api/web/overview)
- [Google Pay website brand guidelines](https://developers.google.com/pay/api/web/guides/brand-guidelines)
- [Google Pay integration checklist](https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist)
- [Google Pay prerequisites](https://developers.google.com/pay/api/web/guides/setup)
  
  - All pages that include Google Pay must be served over HTTPS
  - Your domain must have a TLS domain-validated certificate
  - You must adhere to the [Google Pay API Acceptable Use Policy](https://payments.developers.google.com/terms/aup)
  - You must accept the [Google Pay API Terms of Service](https://payments.developers.google.com/terms/sellertos)

## [Add Google Pay JavaScript library](#add-google-pay-javascript-library)

Include the Google Pay JavaScript library:

```html
<!-- Load the Google Pay JavaScript library -->
<script
  async src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()">
</script>
```

## [Add Google Pay button](#add-google-pay-button)

Add a `div` element to your webpage and use the [Google Pay documentation](https://developers.google.com/pay/api/web/guides/resources/customize) to customize the button type, and to see best practices on using CSS.

Here's sample code for adding a simple black **Buy with Google Pay** button, using the default size and corner radius:

```html
<div id="gpay-button-container"></div>
```

## [Set up Google Pay PaymentsClient](#set-up-google-pay-paymentsclient)

After adding the button, you can set up the PaymentsClient. Start with a base configuration and modify it to your needs:

```javascript
// Environment: TEST or PRODUCTION
// Configure object for a production environment once your implementation testing is completed. environment: 'PRODUCTION'  
const googlePayEnv = 'TEST';

// Moov Account ID
const accountID = 'payer-uuid';

// Bearer token
const bearerToken = 'my token';

// This is the base configuration for all Google Pay payment data requests.
// -- Update `tokenizationSpecification.parameters.gatewayMerchantId` with your own value in the Moov Dashboard.
// -- Update the `merchantInfo.merchantId` and `merchantInfo.merchantName` properties with your own values from Google.
// Moov only supports the following Auth Methods: 'PAN_ONLY' and 'CRYPTOGRAM_3DS' --> Moov does NOT support 3DS from a third-party provider
// Moov only supports the following Card Networks: 'AMEX', 'DISCOVER', 'MASTERCARD' and 'VISA'
const googlePayBaseConfiguration = {
  apiVersion: 2,
  apiVersionMinor: 0,
  allowedPaymentMethods: [
    {
      type: 'CARD',
      parameters: {
        allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
        allowedCardNetworks: ['AMEX', 'DISCOVER', 'MASTERCARD', 'VISA'],
        billingAddressRequired: true,
        billingAddressParameters: {
          format: 'FULL',
        },
      },
      tokenizationSpecification: {
        type: 'PAYMENT_GATEWAY',
        parameters: {
          'gateway': 'moov',
          'gatewayMerchantId': 'a2c4e6g8-i9k1-m3o5-q7s9u1w3y5a7c9e1g'
        }
      },
    },
  ],
  merchantInfo: {
    merchantId: '01234567890123456789',
    merchantName: 'Example Merchant',
  },
  emailRequired: true,
};
```

Now create the PaymentsClient:

```javascript
let googlePayClient = null;

// Create a new PaymentsClient instance.
function getGooglePaymentsClient() {
  if (googlePayClient === null) {
    googlePayClient = new google.payments.api.PaymentsClient({
      environment: googlePayEnv,
    });
  }

  return googlePayClient;
}
```

## [Set up event handlers for page load and Google Pay button click](#set-up-event-handlers-for-page-load-and-google-pay-button-click)

Create an event handler to show the button after the scripts on the page load:

```javascript
function onGooglePayLoaded() {
  paymentRequest = Object.assign({}, googlePayBaseConfiguration);
  
  getGooglePaymentsClient()
    .isReadyToPay(paymentRequest)
    .then(function(res) {
      if (res.result) {
        button = getGooglePaymentsClient().createButton({
          onClick: onGooglePayButtonClick
        });
        document.getElementById('gpay-button-container').appendChild(button);
      } else {
        console.log("Google Pay is not ready for this user.");
      }
    })
    .catch(console.error);
}
```

When the Google Pay button is clicked, update the transaction info:

```javascript
// Moov only supports USD for the United States
function onGooglePayButtonClick() {
  paymentRequest.transactionInfo = {
    totalPriceStatus: 'FINAL',
    totalPrice: '12.34',
    currencyCode: 'USD',
    countryCode: 'US',
  };
  googlePayClient.loadPaymentData(paymentRequest).then(onGooglePayPaymentLoaded).catch(console.error);
}
```

## [Create payment method](#create-payment-method)

Once the customer selects their desired payment method and clicks continue, the client will receive the Google Pay token. Send it to the Moov Platform to get a payment method:

```javascript
// When the token is received from Google Pay, pass the token to the Moov Platform to receive a payment method
function onGooglePayPaymentLoaded(paymentResponse) {
  let url = 'https://api.moov.io/accounts/' + accountID;
  let paymentMethodURL = url + '/google-pay/tokens';

  // Create Moov payment method
  const moovCreatePaymentMethodResponse = fetch(paymentMethodURL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ' + bearerToken,
    },
    body: JSON.stringify({ paymentMethodData: paymentResponse.paymentMethodData })
  }).then(response => {
    response.json();
    });
  }).catch(console.error);
}
```

## [Create Moov transfer](#create-moov-transfer)

Now that you have a Moov payment method associated to the Google Pay token, create a transfer:

```javascript
// Create Moov transfer
let transferURL = url + '/transfers';
const moovTransferResponse = fetch(transferURL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + bearerToken,
    'X-Wait-For': 'rail-response'
  },
  body: JSON.stringify({ paymentMethodID: moovCreatePaymentMethodResponse.paymentMethodID, amount: 12.34 })
}).then(response => {
  response.json();
});
```

Use the `X-Wait-For` [header](/guides/money-movement/events-and-statuses/#transfer-responses) on the transfer request to receive a synchronous response from the card network

```javascript
let status;
if (moovTransferResponse.source.cardDetails.status === 'confirmed') {
  status = 'success';
} else {
  status = 'fail';
}
```

## [Seeing it all together](#seeing-it-all-together)

Here's a sample that synthesizes the steps above all in one place:

```html
<div id="gpay-button-container"></div>
<script type="text/javascript">
  //=============================================================================
  // Configuration
  //=============================================================================

  // Environment: TEST or PRODUCTION
  // Configure object for a production environment once your implementation testing is completed. environment: 'PRODUCTION'  
  const googlePayEnv = 'TEST';

  // Moov Account ID
  const accountID = 'payer-uuid';

  // Bearer token
  const bearerToken = 'my token';

  // This is the base configuration for all Google Pay payment data requests.
  // -- Update `tokenizationSpecification.parameters.gatewayMerchantId` with your own value from Moov.
  // -- Update the `merchantId` and `merchantName` properties with your own values from Google.
  const googlePayBaseConfiguration = {
    apiVersion: 2,
    apiVersionMinor: 0,
    allowedPaymentMethods: [
      {
        type: 'CARD',
        parameters: {
          allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
          allowedCardNetworks: ['AMEX', 'DISCOVER', 'INTERAC', 'JCB', 'MASTERCARD', 'VISA'],
          billingAddressRequired: true,
          billingAddressParameters: {
            format: 'FULL',
          },
        },
        tokenizationSpecification: {
          type: 'PAYMENT_GATEWAY',
          parameters: {
            'gateway': 'moov',
            'gatewayMerchantId': 'a2c4e6g8-i9k1-m3o5-q7s9u1w3y5a7c9e1g'
          }
        },
      },
    ],
    merchantInfo: {
      merchantId: '01234567890123456789',
      merchantName: 'Example Merchant',
    },
    emailRequired: true,
  };

  // Prevent accidental edits to the base configuration
  Object.freeze(googlePayBaseConfiguration);


  //========================
  // Google Payments Client
  //========================
  let googlePayClient = null;

  // Create a new PaymentsClient instance.
  function getGooglePaymentsClient() {
    if (googlePayClient === null) {
      googlePayClient = new google.payments.api.PaymentsClient({
        environment: googlePayEnv,
      });
    }

    return googlePayClient;
  }


  //=========
  // Helpers
  //=========
  let paymentRequest = null;

  //================
  // Event Handlers
  //================

  // Invoked when the pay.js script has completed loading. 
  // The isReadyToPay() method determines if the Google Pay button should be shown.
  //   If the customer is ready to pay (they have a form of payment stored in their Google Wallet) then the Google Pay button is shown.
  function onGooglePayLoaded() {
    paymentRequest = Object.assign({}, googlePayBaseConfiguration);
    
    getGooglePaymentsClient()
      .isReadyToPay(paymentRequest)
      .then(function(res) {
        if (res.result) {
          button = getGooglePaymentsClient().createButton({
            onClick: onGooglePayButtonClick
          });
          document.getElementById('gpay-button-container').appendChild(button);
        } else {
          console.log("Google Pay is not ready for this user.");
        }
      })
      .catch(console.error);
  }

  // Update totalPrice to the intended amount of the transaction
  function onGooglePayButtonClick() {
    paymentRequest.transactionInfo = {
      totalPriceStatus: 'FINAL',
      totalPrice: '12.34',
      currencyCode: 'USD',
      countryCode: 'US',
    };
    googlePayClient.loadPaymentData(paymentRequest).then(onGooglePayPaymentLoaded).catch(console.error);
  }

  // When the token is received from Google Pay, pass the token to the Moov platform to receive a payment method
  function onGooglePayPaymentLoaded(paymentResponse) {
    let url = 'https://api.moov.io/accounts/' + accountID;
    let paymentMethodURL = url + '/google-pay/tokens';

    // Create Moov payment method
    const moovCreatePaymentMethodResponse = fetch(paymentMethodURL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + bearerToken,
      },
      body: JSON.stringify({ paymentMethodData: paymentResponse.paymentMethodData })
    }).then(response => {
      response.json();

      // Create Moov transfer
      let transferURL = url + '/transfers';
      const moovTransferResponse = fetch(transferURL, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ' + bearerToken,
          'X-Wait-For': 'rail-response'
        },
        body: JSON.stringify({ paymentMethodID: moovCreatePaymentMethodResponse.paymentMethodID, amount: 12.34 })
      }).then(response => {
        response.json();
        let status;
        if (moovTransferResponse.source.cardDetails.status === 'confirmed') {
          status = 'success';
        } else {
          status = 'fail';
        }

        // Completes the payment request process and closes the payment sheet
        resolve(status);
      });
    }).catch(console.error);
  }
</script>

<!-- Load the Google Pay JavaScript library -->
<script
  async src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()">
</script>
```

For more information, refer to [Google’s documentation](https://developers.google.com/pay/api/web/guides/tutorial).
