Instant Account Funding - Google Pay

Overview

In addition to Instant Account Funding (PULL from card) with an external card-on-file or with Apple Pay, Synctera offers Instant Account Funding with Google Pay using an external card that the user has added to their Google Wallet. Through this method, transactions are are securely processed with Google Pay’s encryption and authentication features, such as Face ID or Touch ID.

📘

While this guide focuses on web implementation, the conceptual framework applies similarly to Android.

Prerequisites

To perform Instant Account Funding with Google Pay, you must first:

  • Create a Customer
  • Create an Account for the customer
  • Have External Cards enabled with the help of your Synctera implementation representative
  • Perform the necessary steps to enable payments through Google Pay:
    1. Setup your Google Pay environment
    2. Integrate with Google Pay to generate payment token:
      • Present the Google Pay button in your app
      • Present the payment sheet to the customer
      • Receive payment token

Payment Flow

  1. User selects the Google Pay button
  2. Google Pay UI is displayed and user confirms payment
  3. Google Pay returns a payment token
  4. Your application sends the token to your server
  5. Your server requests a transaction with Synctera using the token
  6. Synctera’s payment gateway processes the transaction
  7. A response containing the transaction outcome is returned

See:

Set up your Google Pay environment

1. Set up a Google Pay merchant account

To enable account funding through Google Pay, you need to set up Google Pay for Business. Please follow these instructions.

📘

A Google Pay merchant account is not required for TEST environment

Integrate with Google Pay to generate payment token

1. Include the Google Pay API JavaScript

<script src="<https://pay.google.com/gp/p/js/pay.js>"></script>

2. Define payment configuration

const baseRequest = {
  apiVersion: 2,
  apiVersionMinor: 0
};

const allowedCardNetworks = [
  "MASTERCARD",
  "VISA"
];

const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    'gateway': 'tabapay',
    'gatewayMerchantId': '{{gateway merchant ID}}'
  }
};

const baseCardPaymentMethod = {
  type: 'CARD',
  parameters: {
    allowedAuthMethods: allowedCardAuthMethods,
    allowedCardNetworks: allowedCardNetworks
  }
};

const cardPaymentMethod = Object.assign(
  {tokenizationSpecification: tokenizationSpecification},
  baseCardPaymentMethod
);

const paymentRequest = Object.assign({}, baseRequest);
paymentRequest.allowedPaymentMethods = [cardPaymentMethod];
paymentRequest.transactionInfo = {
  totalPriceStatus: 'FINAL',
  totalPrice: '123.45',
  currencyCode: 'USD',
  countryCode: 'US'
};
paymentRequest.merchantInfo = {
  merchantName: 'Example Merchant', // your merchant Name
  merchantId: '12345678901234567890' // your Google merchant ID
};

allowedCardNetworks: Specify VISA and MASTERCARD

allowedCardAuthMethods: Specify both PAN_ONLY and CRYPTOGRAM_3DS

tokenizationSpecification:

  • gateway: Specify tabapay
  • gatewayMerchantID: Obtain from your Synctera Implementation representative

3. Display the Google Pay button

const paymentsClient = new google.payments.api.PaymentsClient({
  environment: 'TEST' // Use 'PRODUCTION' when going live
});

function checkGooglePayAvailability() {
  const isReadyToPayRequest = Object.assign({}, baseRequest);
  isReadyToPayRequest.allowedPaymentMethods = [baseCardPaymentMethod];

  paymentsClient.isReadyToPay(isReadyToPayRequest)
    .then(function(response) {
      if (response.result) {
        // Google Pay is available - display the button
        createAndAddButton();
      }
    })
    .catch(function(err) {
      console.error("Google Pay availability check error:", err);
    });
}

function createAndAddButton() {
  const button = paymentsClient.createButton({
    onClick: onGooglePayButtonClicked,
    buttonColor: 'black', // 'black' or 'white'
    buttonType: 'buy'
  });
  document.getElementById('googlePayButtonContainer').appendChild(button);
}

function onGooglePayButtonClicked() {
  paymentsClient.loadPaymentData(paymentRequest)
    .then(function(paymentData) {
      // Process payment data
      processPayment(paymentData);
    })
    .catch(function(err) {
      console.error("Payment processing error:", err);
    });
}

4. Process the Payment

function processPayment(paymentData) {
  // Send the payment token to your server
  // The payment token is in paymentData.paymentMethodData.tokenizationData.token
  
  fetch('/your-payment-endpoint', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
    
      paymentToken: paymentData.paymentMethodData.tokenizationData.token
    })
  })
  .then(response => response.json())
  .then(data => {
    // Handle successful payment
    console.log('Payment successful:', data);
    displayPaymentSuccess();
  })
  .catch(error => {
    // Handle payment errors
    console.error('Payment failed:', error);
    displayPaymentError();
  });
}

When a user confirms payment through the Google Pay interface, your application receives an encrypted payment token containing the user's payment credentials. Your client-side code must transmit this token to your server, which then communicates to Synctera’s payment gateway. See next step.

Use the Google Pay payment token to initiate payment

Now that you have generated an Google Pay payment token through your app, your server may request an instant PULL payment using the token. Synctera’s payment gateway will then process the payment, and return the outcome to your app.

Call Create Google Pay External Card Transfer

Example request:

curl \\
  $baseurl/v1/external_cards/transfers/googlepay \\
  -H "Authorization: Bearer $apikey" \\
  -H 'Content-Type: application/json' \\
  -d '
  {
    "type": "GOOGLE_PAY_PULL",
    "originating_account_id": "{{account_id}}",
    "customer_id": "{{customer_id}}",
    "amount": 100,
    "google_pay_payment_data": {
        "api_version": 2,
        "api_version_minor": 0,
        "payment_method_data": {
            "payment_type": "CARD",
            "description": "Visa **** 1234",
            "info": {
                "card_details": "1234",
                "assurance_details": {
                    "account_verified": true,
                    "cardholder_authenticated": true
                },
                "card_network": "VISA",
                "billing_address": {
                    "name": "Name",
                    "postal_code": "12345",
                    "country_code": "US",
                    "phone_number": "555-555-5555",
                    "address_1": "123 Main St",
                    "address_2": "Apt 4B",
                    "address_3": "",
                    "locality": "Anytown",
                    "administrative_area": "CA",
                    "sorting_code": "12345"
                }
            },
            "tokenization_data": {
                "tokenization_type": "PAYMENT_GATEWAY",
                "token": "{\\"signature\\":\\"MEUCIExS6cx4CagjV......"
            }
        }
    }
}'

google_pay_payment_data is populated from paymentData received from Google. Note that the encrypted payment token (paymentData.paymentMethodData.tokenizationData.token) must not be altered and passed exactly as is.

Example response:

{
    "account_id": "41762865-46a8-4b02-a6c4-40f909ae5847",
    "amount": 11,
    "creation_time": "2025-02-26T21:41:21.163735Z",
    "currency": "USD",
    "customer_id": "453101fc-2f42-4aa6-bb84-2acdba064e5c",
    "id": "16980c03-022b-4cf9-90f6-742271132a2a",
    "last_updated_time": "2025-02-26T21:41:22.612429Z",
    "merchant": {
        "address": {
            "address_line_1": "123 Elm St",
            "city": "San Diego",
            "country_code": "US",
            "postal_code": "92101",
            "state": "CA"
        },
        "email": "[email protected]",
        "name": "My Fintech",
        "phone_number": "+18582281234"
    },
    "status": "SUCCEEDED",
    "tenant": "lxpzvp_doyjzy",
    "transaction_id": "0edc0511-ed8d-4bef-83dd-aea8901aa51f",
    "card_details": {
        "address_verification_result": "VERIFIED",
        "cvv2_result": "NOT_SUPPORTED",
        "name_verification_result": "NOT_VERIFIED",
        "pull_details": {
            "country": "US",
            "currency": "USD",
            "network": "Visa",
            "product_type": "CREDIT",
            "regulated": true
        },
        "pull_enabled": true,
        "push_details": {
            "country": "US",
            "currency": "USD",
            "funds_availability": "NOW",
            "network": "Visa",
            "product_type": "CREDIT",
            "regulated": true
        },
        "push_enabled": true,
        "bin": "411111",
        "issuer": "FORD Instiution",
        "last_four": "1111",
        "payment_account_reference": "V0010013022073812195104907179"
    },
    "type": "GOOGLE_PAY_PULL"
}

The status field of the response indicates the outcome of the transaction:

  • SUCCEEDED: The transaction was successful and funds are available - terminal status
  • DECLINED: The transaction could not be completed due to a specific rule (e.g. low balance or velocity control) - terminal status
  • CANCELED: The transaction could not be completed due to error (e.g. upstream processing error) - terminal status
  • UNKNOWN: The transaction status is indeterminate - non-terminal status
  • PENDING: The transaction has been initialized - non-terminal status

Sandbox Testing

  • Use the TEST environment for development
  • Google provides test cards for different scenarios