Google Pay Integration

Process Google Pay payments through the Host-to-Host API with enhanced security features, tokenization, and optimized mobile experience for both Android and web platforms.

Overview

Google Pay integration provides:
  • Enhanced Security: Tokenized payments with device authentication
  • Mobile Optimized: Native Android and web integration
  • Quick Checkout: Streamlined payment experience
  • Biometric Auth: Fingerprint and face authentication support
  • Global Reach: Available in 40+ countries
  • Fraud Protection: Advanced fraud detection and prevention

Required Parameters

Google Pay Specific Fields

ParameterDescriptionRequiredExample
paymentTokenGoogle Pay payment tokenYES”eyJhbGciOiJSUzI1NiIs…”
nameCustomer full nameYES”John Smith”

Customer Information

ParameterDescriptionRequiredExample
emailCustomer email addressYESjohn@example.com
phoneNumberCustomer phone numberYES”+1234567890”
addressCustomer addressYES”123 Main Street”
cityCustomer cityYES”New York”
stateState or provinceYES”NY”
postalCodeZIP or postal codeYES”10001”
countryCountry code (ISO 3166-1)YES”US”

Transaction Details

ParameterDescriptionRequiredExample
amountPayment amountYES99.99
unitCurrency codeYES”USD”
originDomainMerchant domainYES”shop.example.com”
referenceIdMerchant referenceNO”GPY-54321”

Complete Request Example

{
  "name": "John Smith",
  "paymentToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJHb29nbGUiLCJhdWQiOiJtZXJjaGFudC5leGFtcGxlLmNvbSIsInBheW1lbnRNZXRob2QiOnsiZGlzcGxheU5hbWUiOiJWaXNhIOKAoiDigoExMjM0IiwidHlwZSI6IkNBUkQifX0",
  "email": "john@example.com",
  "phoneNumber": "+1234567890",
  "address": "123 Main Street",
  "city": "New York",
  "state": "NY",
  "postalCode": "10001",
  "country": "US",
  "amount": 99.99,
  "unit": "USD",
  "originDomain": "shop.example.com",
  "referenceId": "GPY-54321",
  "notifyUrl": "https://api.example.com/webhook",
  "successUrl": "https://shop.example.com/success",
  "failureUrl": "https://shop.example.com/failure",
  "browserInfo": {
    "browserAcceptHeader": "application/json, text/plain, */*",
    "browserColorDepth": "24",
    "browserIP": "192.168.1.100",
    "browserJavaEnabled": false,
    "browserJavascriptEnabled": true,
    "browserLanguage": "en-US",
    "browserScreenHeight": "1080",
    "browserScreenWidth": "1920",
    "browserTZ": "-300",
    "browserUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  }
}

Implementation Example

JavaScript/Web Integration

// Google Pay API configuration
const baseRequest = {
  apiVersion: 2,
  apiVersionMinor: 0
};

const allowedCardNetworks = ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"];
const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    'gateway': 'cyrexa',
    'gatewayMerchantId': process.env.YONOBI_MERCHANT_ID
  }
};

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

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

const paymentDataRequest = Object.assign({}, baseRequest);
paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
paymentDataRequest.transactionInfo = {
  totalPriceStatus: 'FINAL',
  totalPriceLabel: 'Total',
  totalPrice: '99.99',
  currencyCode: 'USD',
  countryCode: 'US'
};

paymentDataRequest.merchantInfo = {
  merchantId: process.env.GOOGLE_PAY_MERCHANT_ID,
  merchantName: 'Example Store'
};

// Initialize Google Pay
function initializeGooglePay() {
  const paymentsClient = new google.payments.api.PaymentsClient({
    environment: 'TEST' // Change to 'PRODUCTION' for live
  });

  return paymentsClient;
}

// Process Google Pay payment
async function processGooglePayPayment(paymentData, customerInfo) {
  const apiEndpoint = process.env.YONOBI_H2H_ENDPOINT;
  const apiKey = process.env.YONOBI_API_KEY;
  
  try {
    const response = await fetch(apiEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': apiKey
      },
      body: JSON.stringify({
        // Google Pay specific
        name: customerInfo.name,
        paymentToken: paymentData.paymentMethodData.tokenizationData.token,
        
        // Customer info
        email: customerInfo.email,
        phoneNumber: customerInfo.phoneNumber,
        address: customerInfo.address.street,
        city: customerInfo.address.city,
        state: customerInfo.address.state,
        postalCode: customerInfo.address.postalCode,
        country: customerInfo.address.country,
        
        // Transaction
        amount: paymentData.transactionInfo.totalPrice,
        unit: paymentData.transactionInfo.currencyCode,
        originDomain: window.location.hostname,
        referenceId: customerInfo.orderId,
        
        // URLs
        notifyUrl: customerInfo.webhookUrl,
        successUrl: customerInfo.successUrl,
        failureUrl: customerInfo.failureUrl,
        
        // Browser info
        browserInfo: collectBrowserInfo()
      })
    });
    
    const result = await response.json();
    
    if (response.ok) {
      return {
        success: true,
        paymentRequestId: result.paymentRequestId,
        status: result.status,
        transactionId: result.transactionId
      };
    } else {
      return {
        success: false,
        error: result.error,
        message: result.message
      };
    }
  } catch (error) {
    return {
      success: false,
      error: 'NETWORK_ERROR',
      message: error.message
    };
  }
}

// Complete Google Pay flow
async function handleGooglePayPayment() {
  const paymentsClient = initializeGooglePay();
  
  try {
    // Request payment data from Google Pay
    const paymentData = await paymentsClient.loadPaymentData(paymentDataRequest);
    
    // Process payment with Cyrexa
    const result = await processGooglePayPayment(paymentData, {
      name: 'John Smith',
      email: 'john@example.com',
      phoneNumber: '+1234567890',
      address: {
        street: '123 Main Street',
        city: 'New York',
        state: 'NY',
        postalCode: '10001',
        country: 'US'
      },
      orderId: 'GPY-54321',
      webhookUrl: 'https://api.example.com/webhook',
      successUrl: 'https://shop.example.com/success',
      failureUrl: 'https://shop.example.com/failure'
    });
    
    if (result.success) {
      // Payment successful
      window.location.href = '/success?id=' + result.paymentRequestId;
    } else {
      // Handle payment error
      displayError(result.message);
    }
  } catch (error) {
    console.error('Google Pay error:', error);
    displayError('Google Pay payment failed');
  }
}

Android Integration

// Google Pay Android integration
class GooglePayActivity : AppCompatActivity() {
    private lateinit var paymentsClient: PaymentsClient
    private val loadPaymentDataRequestCode = 991
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Initialize Google Pay
        val walletOptions = Wallet.WalletOptions.Builder()
            .setEnvironment(WalletConstants.ENVIRONMENT_TEST) // Change to PRODUCTION
            .build()
        paymentsClient = Wallet.getPaymentsClient(this, walletOptions)
        
        // Check if Google Pay is available
        checkGooglePayAvailability()
    }
    
    private fun checkGooglePayAvailability() {
        val request = IsReadyToPayRequest.fromJson(isReadyToPayRequestJson())
        paymentsClient.isReadyToPay(request)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    // Google Pay is available
                    showGooglePayButton()
                } else {
                    // Google Pay is not available
                    hideGooglePayButton()
                }
            }
    }
    
    private fun requestPayment() {
        val paymentDataRequest = PaymentDataRequest.fromJson(paymentDataRequestJson())
        AutoResolveHelper.resolveTask(
            paymentsClient.loadPaymentData(paymentDataRequest),
            this,
            loadPaymentDataRequestCode
        )
    }
    
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        
        when (requestCode) {
            loadPaymentDataRequestCode -> {
                when (resultCode) {
                    Activity.RESULT_OK -> {
                        data?.let { intent ->
                            val paymentData = PaymentData.getFromIntent(intent)
                            handlePaymentSuccess(paymentData)
                        }
                    }
                    Activity.RESULT_CANCELED -> {
                        // User cancelled
                    }
                    AutoResolveHelper.RESULT_ERROR -> {
                        val status = AutoResolveHelper.getStatusFromIntent(data)
                        handlePaymentError(status)
                    }
                }
            }
        }
    }
    
    private fun handlePaymentSuccess(paymentData: PaymentData) {
        val paymentInfo = paymentData.toJson()
        
        // Process with Cyrexa API
        processYonobiPayment(paymentInfo)
    }
    
    private fun processYonobiPayment(paymentInfo: String) {
        // Implementation to call Cyrexa H2H API
        // Similar to JavaScript example but using Android HTTP client
    }
}

Google Pay Button Integration

HTML Button

<div id="google-pay-button-container">
  <button id="google-pay-button" onclick="handleGooglePayPayment()">
    <img src="https://developers.google.com/pay/api/web/guides/brand-guidelines/google-pay-mark.svg" 
         alt="Google Pay" width="100" height="40">
  </button>
</div>

CSS Styling

#google-pay-button {
  background: #000;
  border: none;
  border-radius: 4px;
  padding: 12px 24px;
  cursor: pointer;
  transition: background-color 0.2s;
}

#google-pay-button:hover {
  background: #333;
}

#google-pay-button:disabled {
  background: #ccc;
  cursor: not-allowed;
}

Payment Token Structure

Google Pay Token Format

{
  "protocolVersion": "ECv2",
  "signature": "MEQCIH6Q4OwQ0jAceFEkGF0JID...",
  "intermediateSigningKey": {
    "signedKey": "{\"keyExpiration\":\"1234567890123\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...\"}",
    "signatures": ["MEQCIH6Q4OwQ0jAceFEkGF0JID..."]
  },
  "signedMessage": "{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtlaN4PK1a/ccDmqJDOLReKbQAjjeLHuQ0...\",\"ephemeralPublicKey\":\"BPhVspn70Zj2Kkgu9t8+ApEuUWsI/zos5whGCQBlgOkuYagOis7qN3RStgeV/QNFqJdN...\",\"encryptedMessage\":\"adMHdWxSfCiTMwXXdMrAgtznpjqecZ...\"}"
}

Error Handling

Common Google Pay Errors

function handleGooglePayError(error) {
  switch (error.statusCode) {
    case 'BUYER_ACCOUNT_ERROR':
      displayError('There was an issue with your Google Pay account');
      break;
    case 'CANCELED':
      // User cancelled - no action needed
      break;
    case 'DEVELOPER_ERROR':
      console.error('Google Pay configuration error:', error);
      displayError('Payment system configuration error');
      break;
    case 'INTERNAL_ERROR':
      displayError('An internal error occurred. Please try again');
      break;
    case 'MERCHANT_ACCOUNT_ERROR':
      displayError('Merchant account error. Please contact support');
      break;
    default:
      displayError('Payment failed. Please try again');
  }
}

Error Response Example

{
  "success": false,
  "error": "GOOGLE_PAY_TOKEN_INVALID",
  "message": "Invalid Google Pay payment token",
  "code": "GP001",
  "details": {
    "tokenValidation": "failed",
    "reason": "Token signature verification failed"
  }
}

Security Features

Token Security

  • Cryptographic Signatures: All tokens are cryptographically signed
  • Time-bound Tokens: Tokens expire after a short period
  • Device Binding: Tokens are bound to specific devices
  • Network Tokenization: Card numbers are replaced with secure tokens

Implementation Security

// Secure token validation
function validateGooglePayToken(token) {
  try {
    // Parse token
    const tokenData = JSON.parse(token);
    
    // Validate required fields
    if (!tokenData.protocolVersion || !tokenData.signature || !tokenData.signedMessage) {
      throw new Error('Invalid token structure');
    }
    
    // Validate protocol version
    if (tokenData.protocolVersion !== 'ECv2') {
      throw new Error('Unsupported protocol version');
    }
    
    return {
      valid: true,
      tokenData: tokenData
    };
  } catch (error) {
    return {
      valid: false,
      error: error.message
    };
  }
}

Testing

Test Environment Setup

// Test configuration
const testConfig = {
  environment: 'TEST',
  merchantId: '01234567890123456789',
  merchantName: 'Test Merchant'
};

// Test payment data
const testPaymentRequest = {
  apiVersion: 2,
  apiVersionMinor: 0,
  allowedPaymentMethods: [{
    type: 'CARD',
    parameters: {
      allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
      allowedCardNetworks: ['VISA', 'MASTERCARD']
    },
    tokenizationSpecification: {
      type: 'PAYMENT_GATEWAY',
      parameters: {
        gateway: 'cyrexa',
        gatewayMerchantId: 'test_merchant_123'
      }
    }
  }],
  transactionInfo: {
    totalPriceStatus: 'FINAL',
    totalPrice: '1.00',
    currencyCode: 'USD'
  },
  merchantInfo: testConfig
};

Test Cards

Google Pay test environment provides these test cards:
  • Visa: 4111111111111111
  • Mastercard: 5555555555554444
  • Amex: 378282246310005

Production Checklist

Before Going Live

  1. Change Environment: Switch from TEST to PRODUCTION
  2. Update Merchant IDs: Use production merchant IDs
  3. SSL Certificate: Ensure valid SSL certificate
  4. Domain Verification: Verify domain with Google
  5. Test Thoroughly: Test all payment flows
  6. Monitor Transactions: Set up transaction monitoring

Production Configuration

// Production configuration
const productionConfig = {
  environment: 'PRODUCTION',
  merchantId: 'your_production_merchant_id',
  merchantName: 'Your Store Name'
};

Best Practices

User Experience

  1. Button Placement: Place Google Pay button prominently
  2. Loading States: Show loading indicators during processing
  3. Error Messages: Provide clear, actionable error messages
  4. Fallback Options: Offer alternative payment methods

Technical Implementation

  1. Token Validation: Always validate payment tokens
  2. Error Handling: Implement comprehensive error handling
  3. Logging: Log all payment attempts for debugging
  4. Security: Follow PCI DSS compliance guidelines

Performance

  1. Lazy Loading: Load Google Pay API only when needed
  2. Caching: Cache availability checks
  3. Timeout Handling: Set appropriate timeouts
  4. Retry Logic: Implement retry logic for failed requests

Next Steps

Apple Pay Integration

Learn about Apple Pay payment integration

Payment Status

Track Google Pay payment status

Webhooks

Handle Google Pay payment notifications