Implement callbacks to customise your Google Pay payment flow for Web.
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.
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.
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.
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 | Description |
|---|---|
dataPreAuthorizationData | Pre-authorisation data including gateway token ID. |
data.gatewayTokenIdstring | The gateway token identifier for the payment. |
| Return value | Description |
|---|---|
GooglePayTransactionInitDataobject | Transaction initialisation data to proceed with payment. |
GooglePayTransactionInitData.psd2Dataobject | PSD2 data including SCA exemption configuration. |
GooglePayTransactionInitData.psd2Data.scaExemptionstring | SCA exemption type: AnonymousCard, LowValue, SecureCorporate, TransactionRiskAnalysis, TrustedBeneficiary. |
GooglePayTransactionInitData.riskScreeningDataobject | Risk screening data for fraud detection. |
GooglePayTransactionInitData.riskScreeningData.performRiskScreeningboolean | Whether to perform risk screening. |
GooglePayTransactionInitData.riskScreeningData.excludeDeviceDataboolean | Whether to exclude device data from risk screening. |
null | Return null to cancel the authorisation. |
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'
}
};
}
};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 | Description |
|---|---|
resultBaseSubmitResult | The transaction result - either MerchantSubmitResult (success) or FailedSubmitResult (failure). |
result.merchantTransactionIdstring | Your unique transaction identifier (present in both success and failure). |
result.systemTransactionIdstring | The PXP system transaction identifier (only in MerchantSubmitResult). |
result.errorCodestring | Error code (only in FailedSubmitResult). |
result.errorReasonstring | Error reason description (only in FailedSubmitResult). |
result.correlationIdstring | Correlation ID for tracking (only in FailedSubmitResult). |
paymentDataAuthorisationPaymentData | The Google Pay payment data collected during checkout. |
paymentData.Emailstring | Customer email address (if email collection was enabled). |
paymentData.ShippingAddressobject | Shipping address (if shipping address collection was enabled). |
paymentData.ShippingOptionobject | Selected shipping option (if shipping options were provided). |
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 });
}
}
};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 | Description |
|---|---|
intermediatePaymentDatagoogle.payments.api.IntermediatePaymentData | The intermediate payment data from Google Pay. |
intermediatePaymentData.callbackTriggerstring | The trigger that caused the callback: INITIALIZE, SHIPPING_ADDRESS, SHIPPING_OPTION, OFFER. |
intermediatePaymentData.shippingAddressobject | The selected shipping address (available when callbackTrigger is SHIPPING_ADDRESS). |
intermediatePaymentData.shippingAddress.countryCodestring | The ISO country code. |
intermediatePaymentData.shippingAddress.postalCodestring | The postal code. |
intermediatePaymentData.shippingAddress.administrativeAreastring | The state or province. |
intermediatePaymentData.shippingAddress.localitystring | The city or locality. |
intermediatePaymentData.shippingOptionDataobject | The selected shipping option (available when callbackTrigger is SHIPPING_OPTION). |
intermediatePaymentData.shippingOptionData.idstring | The shipping option identifier. |
| Return value | Description |
|---|---|
PaymentDataRequestUpdateobject | Updated payment data to display in the Google Pay sheet. |
PaymentDataRequestUpdate.newTransactionInfoobject | Updated transaction information including total and line items. |
PaymentDataRequestUpdate.newTransactionInfo.totalPriceStatusstring | Price status: FINAL or ESTIMATED. |
PaymentDataRequestUpdate.newTransactionInfo.totalPricestring | Updated total price as a string. |
PaymentDataRequestUpdate.newTransactionInfo.displayItemsarray | Array of line items to display. |
PaymentDataRequestUpdate.newShippingOptionParametersobject | Updated shipping options based on address. |
PaymentDataRequestUpdate.errorobject | Error information for invalid addresses or options. |
PaymentDataRequestUpdate.error.reasonstring | Error reason code: SHIPPING_ADDRESS_INVALID, SHIPPING_ADDRESS_UNSERVICEABLE, SHIPPING_OPTION_INVALID. |
PaymentDataRequestUpdate.error.messagestring | User-friendly error message. |
PaymentDataRequestUpdate.error.intentstring | The callback intent that triggered the error: SHIPPING_ADDRESS, SHIPPING_OPTION. |
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 })
};
}
};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 | Description |
|---|---|
eventEvent | The DOM click event. |
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();
}
};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.
This callback receives no parameters.
| Return value | Description |
|---|---|
boolean | Return true to proceed with opening payment sheet, false to prevent opening. |
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
}
};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 | Description |
|---|---|
errorBaseSdkException | The SDK exception containing error details. |
error.namestring | The error type name (e.g., GooglePayNotReadyException). |
error.messagestring | A human-readable error description. |
error.codestring | The error code for programmatic handling. |
error.stackstring | The stack trace for debugging. |
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
});
}
};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.
This callback receives no parameters.
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
);
}
};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.
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(foronPreAuthentication).merchantLegalName(foronPreAuthentication).requestorChallengeIndicator(foronPreAuthentication).scaExemption(foronPreAuthorisation).
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 | Description |
|---|---|
useUnityAuthenticationStrategyboolean | 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 |
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'
}
};
}
});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.
This callback receives no parameters.
| Return value | Description |
|---|---|
PreInitiateAuthenticationConfigobject | Configuration for 3DS pre-authentication. |
PreInitiateAuthenticationConfig.providerIdstring | Your 3DS provider identifier. Optional. |
PreInitiateAuthenticationConfig.requestorAuthenticationIndicatorstring | The authentication indicator. Optional. Possible values:
|
PreInitiateAuthenticationConfig.timeoutnumber | The timeout to get the fingerprint result, in seconds (max 600). Optional. |
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)
};
}
};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 | Description |
|---|---|
dataAuthenticationResult | Object containing the authentication initiation result. |
data.authenticationIdstring | 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.
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);
}
};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.
This callback receives no parameters.
| Return value | Description |
|---|---|
PreAuthenticationConfigobject | Configuration for 3DS authentication. |
PreAuthenticationConfig.merchantCountryNumericCodestring | Your merchant location, as an ISO numeric country code (e.g., 840 for USA, 826 for UK). Optional. |
PreAuthenticationConfig.merchantLegalNamestring | Your legal name. Optional. |
PreAuthenticationConfig.challengeWindowSizenumber | Required. The challenge window size. Possible values:
|
PreAuthenticationConfig.requestorChallengeIndicatorstring | The challenge preference indicator. Optional. Possible values:
|
PreAuthenticationConfig.timeoutnumber | The timeout to get the challenge result, in seconds (max 600). Optional. |
null | Return null to skip the authentication. |
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
};
}
};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 | Description |
|---|---|
dataAuthenticationResult | Object containing authentication result. |
data.authenticationIdstring | 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.
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...');
}
};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.
This callback receives no parameters.
| Return value | Description |
|---|---|
boolean | Return true if consent was given, false otherwise. |
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 storageThis 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.
This callback receives no parameters.
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');
}
};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.
This callback receives no parameters.
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();
}
};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 | Description |
|---|---|
resultBaseSubmitResult | The transaction result containing decline information. |
result.merchantTransactionIdstring | The merchant transaction ID for tracking. |
result.systemTransactionIdstring | The system transaction ID for tracking. |
result.errorCodestring | The error code indicating the type of decline. |
result.errorReasonstring | A human-readable description of the decline reason. |
result.correlationIdstring | The correlation ID for tracking. |
| Return value | Description |
|---|---|
boolean | Return true to retry the payment, false to cancel. |
object | Return an object with retry flag and optional updatedConfigs to retry with modified 3DS authentication settings. |
object.retryboolean | Whether to retry the payment. |
object.updatedConfigsobjectoptional | Updated callback configurations for the retry attempt (e.g., onPreAuthentication with different challenge indicator). |
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;
}
};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');