Skip to content

Events

Implement callbacks to customise your Google Pay payment flow for Web.

Overview

Components emit events based on user interaction or validation. You can use these to implement callback functions, which allow you to inject your own business logic and user experience customisations into the payment flow at critical moments. They ensure that while the SDK handles the complex technical aspects of payment processing, you retain full control over the customer experience and can seamlessly integrate payments into your broader business workflows and systems.

Callbacks enable you to:

  • Validate business rules before payments proceed.
  • Display custom error, failure, or success messages.
  • Tailor user interfaces to match your brand's look and feel.
  • Integrate with your own systems for fraud detection or customer management.
  • Control exactly how your customers experience both successful and failed transactions.
  • Handle Google Pay specific requirements like shipping calculations and dynamic price updates.
  • Integrate 3D Secure authentication for enhanced security.
  • Manage consent for payment tokens and recurring payments.

SDK data callbacks

The Google Pay component requires an SDK initialisation callback to gather shopper information during transaction processing:

  • onGetShopper (required when using consent tokens): Called to retrieve current shopper data (ID, email, name, etc.) for transaction submission to the backend and token association.

This callback ensures the Google Pay component always uses the latest customer data from your application state, forms, or APIs when processing payments and storing payment tokens.

Google Pay-specific events

All Google Pay-specific events are optional and can be mixed and matched based on your business needs.

The SDK initialisation callback (onGetShopper) works alongside Google Pay-specific callbacks to provide a complete payment experience. SDK callbacks handle backend transaction data, while Google Pay callbacks handle the payment sheet interactions and transaction flow.

Payment flow events

onPreAuthorisation

This callback is triggered before payment authorisation, allowing you to provide transaction initialisation data or control whether to proceed.

You can use it to:

  • Integrate with Kount or other fraud detection services.
  • Apply business rules based on transaction amount or customer history.
  • Check product availability before processing payment.
  • Provide risk screening data for fraud prevention.
  • Configure PSD2 SCA exemptions for the transaction.
  • Cancel the payment if business rules aren't met.

Event data

Event dataDescription
data
PreAuthorizationData
Pre-authorisation data including gateway token ID.
data.gatewayTokenId
string
The gateway token identifier for the payment.

Return value

Return valueDescription
GooglePayTransactionInitData
object
Transaction initialisation data to proceed with payment.
GooglePayTransactionInitData.psd2Data
object
PSD2 data including SCA exemption configuration.
GooglePayTransactionInitData.psd2Data.scaExemption
string
SCA exemption type: AnonymousCard, LowValue, SecureCorporate, TransactionRiskAnalysis, TrustedBeneficiary.
GooglePayTransactionInitData.riskScreeningData
object
Risk screening data for fraud detection.
GooglePayTransactionInitData.riskScreeningData.performRiskScreening
boolean
Whether to perform risk screening.
GooglePayTransactionInitData.riskScreeningData.excludeDeviceData
boolean
Whether to exclude device data from risk screening.
nullReturn null to cancel the authorisation.

Example implementation

const googlePayConfig = {
  onPreAuthorisation: async (data) => {
    console.log('Pre-authorisation started');
    console.log('Gateway Token ID:', data.gatewayTokenId);
    
    // Perform pre-payment validation
    const isHighRisk = await checkCustomerRiskProfile();
    const customerTier = await getCustomerTier();
    
    // Check inventory before proceeding
    const inventoryAvailable = await checkInventory();
    if (!inventoryAvailable) {
      showError('Some items are no longer available');
      return null; // Cancel payment
    }
    
    // Check business rules
    const cartTotal = getCurrentCartTotal();
    if (cartTotal > 10000 && isHighRisk) {
      showError('Transaction requires additional verification');
      return null; // Cancel payment for manual review
    }
    
    return {
      riskScreeningData: {
        performRiskScreening: true,
        excludeDeviceData: false
      },
      psd2Data: {
        scaExemption: cartTotal < 30 ? 'LowValue' : 'TransactionRiskAnalysis'
      }
    };
  }
};

onPostAuthorisation

This callback is triggered after the payment is authorised, providing the transaction result and payment data.

You can use it to:

  • Handle successful or declined payments.
  • Redirect customers to success or failure pages.
  • Update inventory and order status.
  • Send order confirmation emails.
  • Record transactions for business intelligence.
  • Display custom success or error messages.
  • Process shipping information collected from Google Pay.
  • Save transaction details for customer account history.

Event data

Event dataDescription
result
BaseSubmitResult
The transaction result - either MerchantSubmitResult (success) or FailedSubmitResult (failure).
result.merchantTransactionId
string
Your unique transaction identifier (present in both success and failure).
result.systemTransactionId
string
The PXP system transaction identifier (only in MerchantSubmitResult).
result.errorCode
string
Error code (only in FailedSubmitResult).
result.errorReason
string
Error reason description (only in FailedSubmitResult).
result.correlationId
string
Correlation ID for tracking (only in FailedSubmitResult).
paymentData
AuthorisationPaymentData
The Google Pay payment data collected during checkout.
paymentData.Email
string
Customer email address (if email collection was enabled).
paymentData.ShippingAddress
object
Shipping address (if shipping address collection was enabled).
paymentData.ShippingOption
object
Selected shipping option (if shipping options were provided).

Example implementation

const googlePayConfig = {
  onPostAuthorisation: async (result, paymentData) => {
    console.log('Payment completed:', result);
    
    if (result && 'merchantTransactionId' in result && !('errorCode' in result)) {
      // Success - MerchantSubmitResult
      console.log('Payment authorised successfully');
      console.log('Transaction ID:', result.merchantTransactionId);
      console.log('System Transaction ID:', result.systemTransactionId);
      
      // Extract payment data
      const email = paymentData.Email;
      const shippingAddress = paymentData.ShippingAddress;
      const shippingOption = paymentData.ShippingOption;
      
      // Update inventory
      await updateInventory(result.merchantTransactionId);
      
      // Create order record
      await createOrder({
        transactionId: result.merchantTransactionId,
        email: email,
        shippingAddress: shippingAddress,
        shippingMethod: shippingOption?.id,
        status: 'confirmed'
      });
      
      // Send confirmation email
      await sendConfirmationEmail({
        transactionId: result.merchantTransactionId,
        email: email,
        shippingAddress: shippingAddress
      });
      
      // Track successful payment
      trackEvent('google-pay-success', {
        transactionId: result.merchantTransactionId,
        cartValue: getCurrentCartValue(),
        shippingMethod: shippingOption?.id
      });
      
      // Update customer account
      await updateCustomerPurchaseHistory(result.merchantTransactionId);
      
      // Redirect to success page
      window.location.href = `/payment-success?txn=${result.merchantTransactionId}`;
      
    } else if (result && 'errorCode' in result) {
      // Failure - FailedSubmitResult
      console.error('Payment declined:', result.errorReason);
      console.error('Error code:', result.errorCode);
      console.error('Correlation ID:', result.correlationId);
      
      // Log failure for monitoring
      logPaymentFailure({
        errorCode: result.errorCode,
        errorReason: result.errorReason,
        correlationId: result.correlationId,
        merchantTransactionId: result.merchantTransactionId
      });
      
      // Show user-friendly error message
      const errorMessage = getErrorMessage(result.errorCode);
      showError(`Payment declined: ${errorMessage}`);
      
      // Track failed payment
      trackEvent('google-pay-declined', {
        errorCode: result.errorCode,
        correlationId: result.correlationId
      });
      
      // Offer alternatives
      showAlternativePaymentMethods();
      
    } else {
      // Payment exception
      console.error('Payment exception:', result);
      showError('Payment processing error. Please contact support.');
      trackEvent('google-pay-exception', { result });
    }
  }
};

Google Pay sheet interaction events

onPaymentDataChanged

This callback is triggered when payment data changes in the Google Pay sheet, such as shipping address or shipping option selection.

You can use it to:

  • Calculate shipping costs based on selected address.
  • Update transaction amounts dynamically.
  • Validate addresses and show errors for unserviceable locations.
  • Add or remove line items based on selections.
  • Calculate taxes based on shipping destination.
  • Apply discounts based on shipping method selection.
  • Check delivery availability for specific locations.

When updating transaction amounts, use the SDK's updateAmount() method to synchronise the amount with the backend session.

Event data

Event dataDescription
intermediatePaymentData
google.payments.api.IntermediatePaymentData
The intermediate payment data from Google Pay.
intermediatePaymentData.callbackTrigger
string
The trigger that caused the callback: INITIALIZE, SHIPPING_ADDRESS, SHIPPING_OPTION, OFFER.
intermediatePaymentData.shippingAddress
object
The selected shipping address (available when callbackTrigger is SHIPPING_ADDRESS).
intermediatePaymentData.shippingAddress.countryCode
string
The ISO country code.
intermediatePaymentData.shippingAddress.postalCode
string
The postal code.
intermediatePaymentData.shippingAddress.administrativeArea
string
The state or province.
intermediatePaymentData.shippingAddress.locality
string
The city or locality.
intermediatePaymentData.shippingOptionData
object
The selected shipping option (available when callbackTrigger is SHIPPING_OPTION).
intermediatePaymentData.shippingOptionData.id
string
The shipping option identifier.

Return value

Return valueDescription
PaymentDataRequestUpdate
object
Updated payment data to display in the Google Pay sheet.
PaymentDataRequestUpdate.newTransactionInfo
object
Updated transaction information including total and line items.
PaymentDataRequestUpdate.newTransactionInfo.totalPriceStatus
string
Price status: FINAL or ESTIMATED.
PaymentDataRequestUpdate.newTransactionInfo.totalPrice
string
Updated total price as a string.
PaymentDataRequestUpdate.newTransactionInfo.displayItems
array
Array of line items to display.
PaymentDataRequestUpdate.newShippingOptionParameters
object
Updated shipping options based on address.
PaymentDataRequestUpdate.error
object
Error information for invalid addresses or options.
PaymentDataRequestUpdate.error.reason
string
Error reason code: SHIPPING_ADDRESS_INVALID, SHIPPING_ADDRESS_UNSERVICEABLE, SHIPPING_OPTION_INVALID.
PaymentDataRequestUpdate.error.message
string
User-friendly error message.
PaymentDataRequestUpdate.error.intent
string
The callback intent that triggered the error: SHIPPING_ADDRESS, SHIPPING_OPTION.

Example implementation

const googlePayConfig = {
  onPaymentDataChanged: async (intermediatePaymentData) => {
    console.log('Payment data changed:', intermediatePaymentData.callbackTrigger);
    
    const baseAmount = 20.00;
    let tax = 5.00;
    let shippingCost = 0;
    let error = null;
    
    // Handle shipping address change
    if (intermediatePaymentData.callbackTrigger === 'SHIPPING_ADDRESS') {
      const address = intermediatePaymentData.shippingAddress;
      
      // Validate address completeness
      if (!address.postalCode || !address.countryCode) {
        error = {
          reason: 'SHIPPING_ADDRESS_INVALID',
          message: 'Please enter a complete address',
          intent: 'SHIPPING_ADDRESS'
        };
      } 
      // Check if we ship to this location
      else if (!['US', 'CA', 'GB'].includes(address.countryCode)) {
        error = {
          reason: 'SHIPPING_ADDRESS_UNSERVICEABLE',
          message: `We do not ship to ${address.countryCode}`,
          intent: 'SHIPPING_ADDRESS'
        };
      }
      // Calculate shipping and tax for valid address
      else {
        // Calculate shipping cost based on location
        shippingCost = await calculateShipping(address);
        
        // Calculate tax based on destination
        tax = await calculateTax(address, baseAmount);
        
        console.log('Shipping calculated:', { shippingCost, tax });
      }
    }
    
    // Handle shipping option change
    if (intermediatePaymentData.callbackTrigger === 'SHIPPING_OPTION') {
      const optionId = intermediatePaymentData.shippingOptionData.id;
      
      // Apply different shipping rates
      const shippingRates = {
        'shipping_standard': 5.00,
        'shipping_express': 15.00,
        'shipping_overnight': 25.00
      };
      
      shippingCost = shippingRates[optionId] || 5.00;
      console.log('Shipping option selected:', optionId, shippingCost);
    }
    
    // Calculate new total
    const newTotal = baseAmount + tax + shippingCost;
    
    // Update SDK amount (synchronizes with backend)
    await pxpSdk.updateAmount(newTotal);
    
    // Return updated payment data
    return {
      newTransactionInfo: {
        totalPriceStatus: 'FINAL',
        totalPrice: newTotal.toFixed(2),
        totalPriceLabel: 'Total',
        displayItems: [
          {
            label: 'Subtotal',
            type: 'LINE_ITEM',
            price: baseAmount.toFixed(2)
          },
          {
            label: 'Tax',
            type: 'TAX',
            price: tax.toFixed(2)
          },
          {
            label: 'Shipping',
            type: 'LINE_ITEM',
            price: shippingCost.toFixed(2)
          }
        ]
      },
      ...(error && { error })
    };
  }
};

onGooglePaymentButtonClicked

This callback is triggered when the Google Pay button is clicked, before the payment sheet opens.

You can use it to:

  • Track button click events for analytics.
  • Perform final validation before opening payment sheet.
  • Show loading indicators.
  • Prepare data for the payment flow.
  • Update cart totals or recalculate amounts.
  • Check inventory availability one last time.

Event data

Event dataDescription
event
Event
The DOM click event.

Example implementation

const googlePayConfig = {
  onGooglePaymentButtonClicked: async (event) => {
    console.log('Google Pay button clicked');
    
    // Track button click
    trackEvent('google-pay-button-clicked', {
      timestamp: new Date().toISOString(),
      cartValue: getCurrentCartValue(),
      itemCount: getCartItemCount()
    });
    
    // Show loading indicator
    showLoadingIndicator();
    
    // Final inventory check
    const inventoryOk = await checkInventory();
    if (!inventoryOk) {
      hideLoadingIndicator();
      showError('Some items are no longer available. Please review your cart.');
      event.preventDefault();
      return;
    }
    
    // Prepare checkout data
    await prepareCheckoutData();
    
    // Update cart totals
    await recalculateCartTotals();
    
    hideLoadingIndicator();
  }
};

Validation and error events

onCustomValidation

This callback is executed before opening the Google Pay payment sheet, allowing custom validation of other form fields.

You can use it to:

  • Validate required form fields before payment.
  • Check terms and conditions acceptance.
  • Verify customer information completeness.
  • Prevent payment sheet from opening if validation fails.
  • Validate minimum order amounts.
  • Check age verification requirements.

Event data

This callback receives no parameters.

Return value

Return valueDescription
booleanReturn true to proceed with opening payment sheet, false to prevent opening.

Example implementation

const googlePayConfig = {
  onCustomValidation: async () => {
    // Validate email
    const email = document.getElementById('email')?.value;
    if (!email || !email.includes('@')) {
      showError('Please enter a valid email address');
      highlightField('email');
      return false;
    }
    
    // Validate phone number (if required)
    const phone = document.getElementById('phone')?.value;
    if (!phone || phone.length < 10) {
      showError('Please enter a valid phone number');
      highlightField('phone');
      return false;
    }
    
    // Validate terms acceptance
    const termsAccepted = document.getElementById('terms')?.checked;
    if (!termsAccepted) {
      showError('Please accept the terms and conditions');
      highlightField('terms');
      return false;
    }
    
    // Validate age verification (if required)
    const ageVerified = document.getElementById('age-verify')?.checked;
    if (!ageVerified) {
      showError('You must be 18 or older to complete this purchase');
      return false;
    }
    
    // Validate minimum order amount
    const cartTotal = getCurrentCartTotal();
    if (cartTotal < 10.00) {
      showError('Minimum order amount is $10.00');
      return false;
    }
    
    // Final inventory check
    const inventoryAvailable = await checkInventory();
    if (!inventoryAvailable) {
      showError('Some items are no longer available. Please review your cart.');
      return false;
    }
    
    return true; // All validations passed
  }
};

onError

This callback is triggered when an error occurs during the Google Pay payment process.

You can use it to:

  • Log errors for debugging and monitoring.
  • Display user-friendly error messages.
  • Offer alternative payment methods.
  • Implement automatic retry for transient errors.
  • Send error notifications to support teams.
  • Track error rates for quality monitoring.

Event data

Event dataDescription
error
BaseSdkException
The SDK exception containing error details.
error.name
string
The error type name (e.g., GooglePayNotReadyException).
error.message
string
A human-readable error description.
error.code
string
The error code for programmatic handling.
error.stack
string
The stack trace for debugging.

Example implementation

const googlePayConfig = {
  onError: (error) => {
    console.error('Google Pay error:', error);
    
    // Log error for debugging
    logError('google-pay-error', {
      name: error.name,
      message: error.message,
      code: error.code,
      stack: error.stack,
      timestamp: new Date().toISOString(),
      userId: getCurrentUserId(),
      sessionId: getSessionId()
    });
    
    // Handle different error types
    if (error.name === 'GooglePayPaymentFailedException' && error.message.includes('cancel')) {
      // User cancelled - silent handling
      console.log('User cancelled Google Pay');
      trackEvent('google-pay-user-cancelled');
      return;
    } 
    
    if (error.name === 'GooglePayNotReadyException') {
      showUserMessage('Google Pay is not available on this device. Please use an alternative payment method.');
      showAlternativePaymentMethods();
      trackEvent('google-pay-not-available');
    } 
    
    else if (error.name === 'GooglePayPaymentFailedException' && error.message.includes('HTTPS')) {
      showUserMessage('Secure connection required. Please ensure your site uses HTTPS.');
      notifySupport('HTTPS requirement not met');
    }
    
    else if (error.name === 'GooglePayConfigurationValidationFailedException') {
      showUserMessage('Payment system temporarily unavailable. Please try again later.');
      notifySupport('Merchant configuration error', error);
    }
    
    else if (error.message.includes('Network')) {
      showUserMessage('Network error. Please check your connection and try again.');
      // Offer retry option
      showRetryButton();
    } 
    
    else {
      showUserMessage('Payment failed. Please try again or use a different payment method.');
      showAlternativePaymentMethods();
    }
    
    // Track error for monitoring
    trackEvent('google-pay-error', {
      errorType: error.name,
      errorCode: error.code
    });
  }
};

onCancel

This callback is triggered when the customer cancels the Google Pay payment flow.

You can use it to:

  • Track cancellation rates for conversion optimisation.
  • Show helpful messages or alternative options.
  • Save the customer's cart for later completion.
  • Trigger email campaigns for abandoned checkouts.
  • Understand drop-off points in the payment flow.
  • Offer assistance or live chat support.

Event data

This callback receives no parameters.

Example implementation

const googlePayConfig = {
  onCancel: () => {
    console.log('Google Pay cancelled');
    
    // Track cancellation for analytics
    trackEvent('google-pay-cancelled', {
      timestamp: new Date().toISOString(),
      cartValue: getCurrentCartValue(),
      itemCount: getCartItemCount(),
      pageUrl: window.location.href
    });
    
    // Preserve cart for later
    saveCartForLater();
    
    // Show helpful message
    showMessage(
      'No worries! Your items are saved. You can complete your purchase anytime.', 
      'info'
    );
    
    // Offer live chat support
    if (getCartValue() > 100) {
      showLiveChatOffer('Need help completing your purchase?');
    }
    
    // Offer alternatives after a short delay
    setTimeout(() => {
      showAlternativePaymentOptions();
    }, 2000);
    
    // Schedule abandoned cart email
    scheduleAbandonedCartEmail(
      getCustomerEmail(), 
      getCurrentCartData(),
      60 // Send after 60 minutes
    );
  }
};

3D Secure authentication events

Google Pay supports full 3DS authentication through the AuthenticationConfig interface. These events allow you to control the 3D Secure authentication flow.

For detailed 3DS configuration and implementation guidance, see the 3D Secure documentation.

useUnityAuthenticationStrategy

This configuration parameter controls which authentication strategy is used for 3DS authentication.

When set to true, Unity handles the authentication strategy automatically, and you aren't required to provide the following configuration parameters:

  • merchantCountryNumericCode (for onPreAuthentication).
  • merchantLegalName (for onPreAuthentication).
  • requestorChallengeIndicator (for onPreAuthentication).
  • scaExemption (for onPreAuthorisation).

Using Unity authentication strategy simplifies 3DS implementation by reducing the number of required configuration parameters. Unity will automatically provide optimal values based on the transaction context.

Configuration

ConfigurationDescription
useUnityAuthenticationStrategy
boolean
When true, uses Unity authentication strategy and automatically handles merchant authentication configuration. When false or not specified, uses the default authentication strategy where merchant must provide all configuration.

Default: false

Example implementation

With Unity authentication strategy (simplified):

const googlePayButton = pxpSdk.create('google-pay-button', {
  // ... other configuration
  
  // Use Unity authentication strategy
  useUnityAuthenticationStrategy: true,
  
  onPreInitiateAuthentication: () => {
    return {
      providerId: 'pxpfinancial',
      timeout: 12
    };
  },
  
  onPreAuthentication: async () => {
    // Simplified - no need to provide merchantCountryNumericCode, 
    // merchantLegalName, or requestorChallengeIndicator
    return {
      challengeWindowSize: 4
    };
  },
  
  onPreAuthorisation: async (data) => {
    // No need to provide scaExemption when using Unity strategy
    return {
      riskScreeningData: {
        performRiskScreening: true
      }
    };
  }
});

Without Unity authentication strategy (default):

const googlePayButton = pxpSdk.create('google-pay-button', {
  // ... other configuration
  
  // useUnityAuthenticationStrategy: false, // Default
  
  onPreInitiateAuthentication: () => {
    return {
      providerId: 'pxpfinancial',
      timeout: 12
    };
  },
  
  onPreAuthentication: async () => {
    // All parameters required when not using Unity strategy
    return {
      merchantCountryNumericCode: '840',
      merchantLegalName: 'Your Store',
      challengeWindowSize: 4,
      requestorChallengeIndicator: '02'
    };
  },
  
  onPreAuthorisation: async (data) => {
    return {
      riskScreeningData: {
        performRiskScreening: true
      },
      psd2Data: {
        scaExemption: 'LowValue'
      }
    };
  }
});

onPreInitiateAuthentication

This callback is triggered before initiating the 3DS pre-authentication check.

You can use it to:

  • Configure 3DS provider settings.
  • Set authentication request preferences.
  • Specify timeout values for authentication requests.
  • Control the initial authentication flow.

Event data

This callback receives no parameters.

Return value

Return valueDescription
PreInitiateAuthenticationConfig
object
Configuration for 3DS pre-authentication.
PreInitiateAuthenticationConfig.providerId
string
Your 3DS provider identifier. Optional.
PreInitiateAuthenticationConfig.requestorAuthenticationIndicator
string
The authentication indicator. Optional.

Possible values:
  • 01 (Payment transaction)
  • 02 (Recurring transaction)
  • 03 (Installment transaction)
  • 04 (Add card)
  • 05 (Maintain card)
  • 06 (Cardholder verification)
  • 07 (Billing agreement)
  • 08 (Split shipment)
  • 09 (Delayed shipment)
  • 10 (Split payment)
PreInitiateAuthenticationConfig.timeout
number
The timeout to get the fingerprint result, in seconds (max 600). Optional.

Example implementation

const googlePayConfig = {
  onPreInitiateAuthentication: () => {
    console.log('Initiating 3DS pre-authentication');
    
    // Track 3DS initiation
    trackEvent('3ds-pre-initiate');
    
    return {
      providerId: 'your-3ds-provider-id', // Optional - your 3DS provider identifier
      requestorAuthenticationIndicator: '01', // Payment transaction
      timeout: 300 // 5 minutes (300 seconds)
    };
  }
};

onPostInitiateAuthentication

This callback is triggered after the 3DS pre-authentication check completes.

You can use it to:

  • Retrieve authentication assessment results.
  • Determine if full authentication is required.
  • Log authentication initiation for compliance.
  • Check SCA requirements and exemptions.
  • Decide whether to proceed with challenge.

Event data

Event dataDescription
data
AuthenticationResult
Object containing the authentication initiation result.
data.authenticationId
string
The unique identifier for this 3DS session. Use this ID to retrieve full PreInitiateAuthentication result from Unity backend.

Use the authenticationId with the Get 3DS pre-initiate authentication details API to retrieve pre-authentication results including SCA mandates, exemptions, and 3DS support.

Example implementation

const googlePayConfig = {
  onPostInitiateAuthentication: async (data) => {
    console.log('3DS pre-initiation completed. Authentication ID:', data.authenticationId);
    
    // Retrieve initiate authentication result from Unity
    const authResult = await fetchAuthenticationResultFromBackend(data.authenticationId);
    
    // Check if authentication setup was successful
    if (authResult.state === 'PendingClientData') {
      console.log('Waiting for client data collection');
    }
    
    // Check if SCA (Strong Customer Authentication) is mandated
    if (authResult.scaMandated) {
      console.log('SCA is required - 3DS must complete successfully');
      showMessage('Additional verification required');
    }
    
    // Check available exemptions
    if (authResult.applicableExemptions === 'LVP') {
      console.log('Low value exemption available');
    } else if (authResult.applicableExemptions === 'TRA') {
      console.log('Transaction risk analysis exemption available');
    }
    
    // Evaluate the result to update authentication decision
    const decision = await evaluateAuthenticationAndUpdateSession(authResult);
  }
};

onPreAuthentication

This callback is triggered before full 3DS authentication begins, allowing you to provide authentication configuration.

You can use it to:

  • Specify merchant details for authentication.
  • Configure challenge window preferences.
  • Set challenge indicators based on risk assessment.
  • Provide country-specific merchant information.
  • Control the authentication user experience.

Event data

This callback receives no parameters.

Return value

Return valueDescription
PreAuthenticationConfig
object
Configuration for 3DS authentication.
PreAuthenticationConfig.merchantCountryNumericCode
string
Your merchant location, as an ISO numeric country code (e.g., 840 for USA, 826 for UK). Optional.
PreAuthenticationConfig.merchantLegalName
string
Your legal name. Optional.
PreAuthenticationConfig.challengeWindowSize
number
Required. The challenge window size.

Possible values:
  • 1 (250x400)
  • 2 (390x400)
  • 3 (500x600)
  • 4 (600x400)
  • 5 (Full screen)
PreAuthenticationConfig.requestorChallengeIndicator
string
The challenge preference indicator. Optional.

Possible values:
  • 01 (No preference)
  • 02 (No challenge requested)
  • 03 (Challenge requested: Merchant preference)
  • 04 (Challenge requested: Mandate)
  • 05 (No challenge requested: TRA performed)
  • 06 (No challenge requested: Data share only)
  • 07 (No challenge requested: SCA already performed)
  • 08 (No challenge requested: Trust list exemption)
  • 09 (Challenge requested: Trust list prompt)
  • 10 (No challenge requested: Low value exemption)
  • 11 (No challenge requested: Secure corporate payment)
  • 12 (Challenge requested: Device binding prompt)
  • 13 (Challenge requested: Issuer requested)
  • 14 (Challenge requested: MIT)
PreAuthenticationConfig.timeout
number
The timeout to get the challenge result, in seconds (max 600). Optional.
nullReturn null to skip the authentication.

Example implementation

const googlePayConfig = {
  onPreAuthentication: async () => {
    console.log('Starting 3DS authentication');
    
    // Get merchant configuration
    const merchantConfig = await getMerchantConfiguration();
    
    // Assess transaction risk
    const riskLevel = await assessTransactionRisk();
    
    // Determine challenge indicator based on risk
    let challengeIndicator = '01'; // No preference
    if (riskLevel === 'high') {
      challengeIndicator = '04'; // Challenge required
    } else if (riskLevel === 'low') {
      challengeIndicator = '02'; // No challenge requested
    }
    
    // Track authentication start
    trackEvent('3ds-authentication-started', {
      riskLevel,
      challengeIndicator
    });
    
    return {
      merchantCountryNumericCode: '840', // USA
      merchantLegalName: merchantConfig.legalName,
      challengeWindowSize: 5, // Full screen for best UX
      requestorChallengeIndicator: challengeIndicator,
      timeout: 600 // 10 minutes (600 seconds) - max value
    };
  }
};

onPostAuthentication

This callback is triggered after 3DS authentication completes, providing the authentication result.

You can use it to:

  • Retrieve authentication results.
  • Log authentication outcomes for compliance.
  • Track authentication success rates.
  • Handle authentication failures gracefully.
  • Record ECI values and authentication indicators.

Event data

Event dataDescription
data
AuthenticationResult
Object containing authentication result.
data.authenticationId
string
The unique identifier for the authentication attempt. Use this ID to retrieve full authentication details from the Unity backend.

Use the authenticationId with the Get 3DS authentication details API to retrieve the full authentication results including transaction status, ECI values, and CAVV data.

Example implementation

const googlePayConfig = {
  onPostAuthentication: async (data) => {
    console.log('3DS authentication completed. Authentication ID:', data.authenticationId);
    
    // Send authenticationId to backend to retrieve authentication result
    const authResult = await fetchAuthenticationResultFromBackend(data.authenticationId);
    
    console.log('Authentication result:', authResult);
    
    // Check transaction status
    switch (authResult.transactionStatus) {
      case 'Y':
        console.log('Authentication successful - no challenge needed');
        showMessage('Card verified successfully');
        break;
        
      case 'C':
        console.log('Challenge completed - checking result...');
        if (authResult.state === 'AuthenticationSuccessful') {
          console.log('Challenge completed successfully');
          showMessage('Verification completed');
        } else {
          console.log('Challenge failed');
          showError('Verification failed. Please try again.');
          return; // Stop payment
        }
        break;
        
      case 'N':
        console.log('Authentication failed');
        showError('Card verification failed');
        return; // Stop payment
        
      case 'R':
        console.log('Authentication rejected');
        showError('Payment was rejected by your bank');
        return; // Stop payment
    }
    
    // Evaluate authentication result to update authorisation decision
    const authorisationDecision = await evaluateAuthenticationAndUpdateAuthorization(authResult);
    
    console.log('Proceeding to final authorisation...');
  }
};

onGetConsent

This callback is called to determine if the customer has given consent to store their payment token for future use.

The primary use case is to set a default consent value (true or false) when you're not rendering the google-pay-consent checkbox component. This allows you to control token storage behaviour without requiring explicit customer interaction.

When both googlePayConsentComponent and onGetConsent are provided, the consent component value takes priority. The onGetConsent callback will not be called if a consent component is linked.

You can use it to:

  • Set a default consent value when not using the consent checkbox component.
  • Check custom consent checkbox status from your own UI.
  • Verify terms and conditions acceptance for stored payments.
  • Control token storage behaviour based on business logic.
  • Implement opt-in/opt-out for recurring payments.
  • Respect customer privacy preferences.

Event data

This callback receives no parameters.

Return value

Return valueDescription
booleanReturn true if consent was given, false otherwise.

Example implementation

Example 1: Set default consent value without checkbox

const googlePayButton = pxpSdk.create('google-pay-button', {
  // ... payment configuration
  
  onGetConsent: () => {
    // Return a default value when not using consent checkbox
    // Set to true to always store tokens, false to never store
    return true; // Always save payment method for this merchant
  },
  
  onPostAuthorisation: (result, paymentData) => {
    if (result && 'merchantTransactionId' in result) {
      console.log('Payment successful, token will be stored');
      // Token storage is handled automatically based on consent
    }
  }
});

Example 2: Use custom consent checkbox from your UI

const googlePayButton = pxpSdk.create('google-pay-button', {
  // ... payment configuration
  
  onGetConsent: () => {
    // Check your own custom checkbox
    const consentGiven = document.getElementById('save-payment-checkbox')?.checked || false;
    
    if (consentGiven) {
      console.log('Customer consented to save payment method');
      
      // Track consent
      trackEvent('payment-consent-given', {
        timestamp: new Date().toISOString(),
        paymentMethod: 'google-pay'
      });
    } else {
      console.log('Customer did not consent to save payment method');
    }
    
    return consentGiven;
  }
});

Example 3: With consent component (component value takes priority)

// Create consent component
const googlePayConsent = pxpSdk.create('google-pay-consent', {
  label: 'Save my payment method for future purchases',
  checked: false
});
googlePayConsent.mount('consent-container');

const googlePayButton = pxpSdk.create('google-pay-button', {
  // ... payment configuration
  
  // Link the consent component
  googlePayConsentComponent: googlePayConsent,
  
  // This callback will NOT be called because consent component is linked
  onGetConsent: () => {
    return true; // This is ignored when consent component is present
  }
});

// The consent component's checked state will be used for token storage

Risk screening events

onKountCollectStart

This callback is triggered when Kount fraud screening data collection begins.

You can use it to:

  • Track fraud screening initiation.
  • Show loading indicators during screening.
  • Log screening events for compliance.
  • Monitor fraud detection performance.

Event data

This callback receives no parameters.

Example implementation

const googlePayConfig = {
  onKountCollectStart: () => {
    console.log('Kount fraud screening started');
    
    // Track screening start
    trackEvent('kount-screening-started', {
      timestamp: new Date().toISOString()
    });
    
    // Show loading indicator
    showMessage('Verifying transaction...', 'info');
  }
};

onKountCollectEnd

This callback is triggered when Kount fraud screening data collection completes.

You can use it to:

  • Track fraud screening completion.
  • Hide loading indicators.
  • Log screening results.
  • Process fraud scores.

Event data

This callback receives no parameters.

Example implementation

const googlePayConfig = {
  onKountCollectEnd: () => {
    console.log('Kount fraud screening completed');
    
    // Track screening completion
    trackEvent('kount-screening-completed', {
      timestamp: new Date().toISOString(),
      duration: getScreeningDuration()
    });
    
    // Hide loading indicator
    hideMessage();
  }
};

Soft decline retry events

onPreRetrySoftDecline

This callback is triggered before retrying a soft-declined payment with different authentication parameters.

You can use it to:

  • Configure retry attempts with alternative challenge indicators.
  • Implement custom retry logic for soft declines.
  • Track soft decline occurrences.
  • Adjust authentication parameters for better success rates.

Event data

Event dataDescription
result
BaseSubmitResult
The transaction result containing decline information.
result.merchantTransactionId
string
The merchant transaction ID for tracking.
result.systemTransactionId
string
The system transaction ID for tracking.
result.errorCode
string
The error code indicating the type of decline.
result.errorReason
string
A human-readable description of the decline reason.
result.correlationId
string
The correlation ID for tracking.

Return value

Return valueDescription
booleanReturn true to retry the payment, false to cancel.
objectReturn an object with retry flag and optional updatedConfigs to retry with modified 3DS authentication settings.
object.retry
boolean
Whether to retry the payment.
object.updatedConfigs
objectoptional
Updated callback configurations for the retry attempt (e.g., onPreAuthentication with different challenge indicator).

Example implementation

const googlePayConfig = {
  onPreRetrySoftDecline: (result) => {
    console.log('Soft decline occurred, preparing retry');
    console.log('Merchant Transaction ID:', result.merchantTransactionId);
    console.log('System Transaction ID:', result.systemTransactionId);
    console.log('Error code:', result.errorCode);
    console.log('Decline reason:', result.errorReason);
    console.log('Correlation ID:', result.correlationId);
    
    // Track soft decline
    trackEvent('payment-soft-decline', {
      merchantTransactionId: result.merchantTransactionId,
      systemTransactionId: result.systemTransactionId,
      errorCode: result.errorCode,
      errorReason: result.errorReason,
      correlationId: result.correlationId
    });
    
    // Show message to user
    showMessage('Processing payment with additional verification...', 'info');
    
    // Retry with forced 3DS challenge
    return {
      retry: true,
      updatedConfigs: {
        onPreInitiateAuthentication: () => ({
          providerId: 'pxpfinancial',
          timeout: 12
        }),
        onPreAuthentication: async () => ({
          merchantCountryNumericCode: '826',
          merchantLegalName: 'Your Store Ltd',
          challengeWindowSize: 5,
          requestorChallengeIndicator: '04' // Force challenge on retry
        })
      }
    };
    
    // Or simply return true to retry with same config:
    // return true;
    
    // Or return false to cancel retry:
    // return false;
  }
};

Complete implementation example

Here's a complete example showing how multiple callbacks work together:

// Initialise SDK
const pxpSdk = window.PXPCheckout.init({
  merchantGroupName: process.env.REACT_APP_MERCHANT_GROUP,
  merchantName: process.env.REACT_APP_MERCHANT_NAME,
  environment: 'test'
});

// Create consent component
const googlePayConsent = pxpSdk.create('google-pay-consent', {});
googlePayConsent.mount('consent-container');

// Create Google Pay button with comprehensive event handling
const googlePayButton = pxpSdk.create('google-pay-button', {
  paymentDataRequest: {
    allowedPaymentMethods: [{
      type: 'CARD',
      parameters: {
        allowedCardNetworks: ['VISA', 'MASTERCARD', 'AMEX'],
        allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS']
      }
      // Note: tokenizationSpecification is automatically configured by the SDK from session data
    }],
    transactionInfo: {
      currencyCode: 'GBP',
      totalPriceStatus: 'FINAL',
      totalPrice: '25.00'
    },
    emailRequired: true,
    shippingAddressRequired: true,
    callbackIntents: ['SHIPPING_ADDRESS', 'SHIPPING_OPTION']
  },
  
  googlePayConsentComponent: googlePayConsent,
  
  // Pre-authorisation
  onPreAuthorisation: async (data) => {
    const cartTotal = getCurrentCartTotal();
    
    return {
      riskScreeningData: {
        performRiskScreening: true
      },
      psd2Data: {
        scaExemption: cartTotal < 30 ? 'LowValue' : 'TransactionRiskAnalysis'
      }
    };
  },
  
  // Post-authorisation
  onPostAuthorisation: async (result, paymentData) => {
    if (result && 'merchantTransactionId' in result && !('errorCode' in result)) {
      await updateInventory(result.merchantTransactionId);
      await sendConfirmationEmail({
        transactionId: result.merchantTransactionId,
        email: paymentData.Email
      });
      window.location.href = `/success?txn=${result.merchantTransactionId}`;
    } else if (result && 'errorCode' in result) {
      showError(`Payment declined: ${result.errorReason}`);
    }
  },
  
  // Payment sheet interactions
  onPaymentDataChanged: async (intermediatePaymentData) => {
    const baseAmount = 20.00;
    let tax = 5.00;
    let shippingCost = 0;
    
    if (intermediatePaymentData.shippingAddress) {
      shippingCost = await calculateShipping(intermediatePaymentData.shippingAddress);
      tax = await calculateTax(intermediatePaymentData.shippingAddress, baseAmount);
    }
    
    const newTotal = baseAmount + tax + shippingCost;
    await pxpSdk.updateAmount(newTotal);
    
    return {
      newTransactionInfo: {
        totalPriceStatus: 'FINAL',
        totalPrice: newTotal.toFixed(2),
        displayItems: [
          { label: 'Subtotal', type: 'LINE_ITEM', price: baseAmount.toFixed(2) },
          { label: 'Tax', type: 'TAX', price: tax.toFixed(2) },
          { label: 'Shipping', type: 'LINE_ITEM', price: shippingCost.toFixed(2) }
        ]
      }
    };
  },
  
  // Custom validation
  onCustomValidation: async () => {
    const email = document.getElementById('email')?.value;
    if (!email || !email.includes('@')) {
      showError('Please enter a valid email address');
      return false;
    }
    return true;
  },
  
  // Error handling
  onError: (error) => {
    console.error('Google Pay error:', error);
    logError('google-pay-error', error);
    
    if (!(error.name === 'GooglePayPaymentFailedException' && error.message.includes('cancel'))) {
      showError('Payment failed. Please try again or use a different payment method.');
    }
  },
  
  // Cancellation handling
  onCancel: () => {
    trackEvent('google-pay-cancelled', { cartValue: getCurrentCartValue() });
    saveCartForLater();
  },
  
  // Consent handling
  onGetConsent: () => {
    return document.getElementById('save-payment-checkbox')?.checked || false;
  }
});

// Mount button
googlePayButton.mount('google-pay-container');