& More

Google Pay™

Google Pay enables users to pay with their card information, which is securely stored by Google, without the cumbersome process of entering card and payment information on a website.

This example shows how you can process Google Pay payments using our shift4.js.

Payment with the Google Pay API JavaScript library

To support Google Pay for the widest audience, we advise using the Google Pay API JavaScript library.

The entire process is detailed in the code snippets below and can be organized into the following main sections:

  • Load shift4.js and Google Pay API JavaScript library [1]
  • Setup Shift4.js with your public key [2]
    • Your public key is also a Shift4's merchant identifier in Google Pay [2i]
  • Initialize Google's PaymentClient with proper environment [3]
  • Setup payment button [4]
    • Check if Google Pay is available in the browser [4a]
    • Configure Google Pay button and add it to the page [4b]
  • Proceed with payment on button click [5]
    • Load payment data [5a]
    • Setup Payment Method object, including optional 3DS process [5b]
    • Create charge [5c]
    • Show result [5d]

Payment button configuration details

In steps 4, 5, and 6, code uses details that are utilized by Google's SDK to display payment sheet and generate final token. Those details are configured in following functions:

  • getAllowedPaymentMethod configures supported card networks and tokenization details that will allow our API to decode payment token successfully.
  • createGooglePaymentDataRequest uses getAllowedPaymentMethod, but also defines transaction and payment process specific information like its currency, amount and merchant display name.

Advanced Google Pay setup

This page shows a basic integration example of Google Pay and our API. If you want to get better understanding of Google Pay API or want to better understand more complex possibilities, please refer to official Google Pay Web developer tutorial

Google Pay and 3D Secure Requirement

There are two types of Google Pay tokens: PAN_ONLY and CRYPTOGRAM_3DS.

In case of a CRYPTOGRAM_3DS token 3D Secure data are embedded into the token and there are no additional requirements before making payment with it.

In case of a PAN_ONLY token there is an additional requirement to perform 3D Secure before creating a charge. See next section to see how it is achieved using our API.

Google Pay and 3D Secure in Shift4

Thanks to our Payment Method API you don't have to distinguish between the two token types and just start 3D Secure when our API ask you to.

To do so create Payment Method of type google_pay with received token and then use it as source for Payment Method of type three_d_secure. Our system will decide whether additional 3D Secure verification is actually required and will respond accordingly.

  • If supplied token was of type CRYPTOGRAM_3DS Payment Method would be in chargeable status and you can create Charge with it right away.
  • If supplied token was of type PAN_ONLY Payment Method would be in pending status and have three_d_secure value in flow.nextAction property. This indicates you should perform 3D Secure verification before doing payment, as shown in the example. After 3D Secure is performed payment method would change its status and you can create the charge.

Official Google Pay's usage guidelines, policies and documentation

Before using Google Pay payments on your website, be sure to read through the official guidelines written by Google:

Also keep in mind that to use this integration you must adhere to the following policies:

And if you want to learn more about Google Pay from developer perspective please refer to:

class ExamplesAjaxChargeWithGooglePayController {
    Map googlePayWithThreeDSecurePaymentMethod(@RequestBody GooglePayPaymentMethodExampleRequest exampleRequest) throws IOException {
        try (Shift4Gateway shift4Gateway = createShift4Gateway()) {
            PaymentMethodRequest googlePayRequest = new PaymentMethodRequest((String) null)
                    .set("type", "google_pay")
                    .set("googlePay", Map.of("token", exampleRequest.googlePayToken));
            PaymentMethod googlePayPaymentMethod = shift4Gateway.createPaymentMethod(googlePayRequest);

            PaymentMethodRequest threeDSecureRequest = new PaymentMethodRequest((String) null)
                    .set("type", "three_d_secure")
                    .set("source", googlePayPaymentMethod.getId())
                    .set("threeDSecure", Map.of(
                            "amount", 100,
                            "currency", "USD"
            PaymentMethod threeDSecurePaymentMethod = shift4Gateway.createPaymentMethod(threeDSecureRequest);

            return singletonMap("clientObjectId", threeDSecurePaymentMethod.getClientObjectId());

        } catch (Shift4Exception e) {
            throw new BadRequestException(e.getMessage());

    static class GooglePayPaymentMethodExampleRequest {
        Object googlePayToken;

    Map chargeWithGooglePayPayment(@RequestBody GooglePayPaymentExampleRequest exampleRequest) throws IOException {
        try (Shift4Gateway shift4Gateway = createShift4Gateway()) {
            // find saved `id` of Payment Method using public `clientObjectId`
            var paymentMethodId = getIdOfPaymentMethod(exampleRequest.paymentMethod);

            // create charge using created payment method
            ChargeRequest chargeRequest = new ChargeRequest(100, "USD")
                    .paymentMethod(new PaymentMethodRequest(paymentMethodId));
            Charge charge = shift4Gateway.createCharge(chargeRequest);

            // pass clientObjectId of charge to frontend
            return singletonMap("clientObjectId", charge.getClientObjectId());
        } catch (Shift4Exception e) {
            throw new BadRequestException(e.getMessage());

    static class GooglePayPaymentExampleRequest {
        String  paymentMethod;

    private void validateUsageOfPaymentMethod(String paymentMethodClientObjectId) {
        // validate method usage here, it highly depends on backend implementation
        // you should ensure that clientObjectId is used by the same user that configured it in the previous step