Skip to content

Events

Implement callbacks to customise your Paze 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 Paze specific popup and decryption flow requirements.

SDK data callbacks

Configure these callbacks on PxpCheckout.initialize(), not on the paze-button component. They supply shopper and shipping data when the SDK builds the Unity transaction request after decryption.

  • onGetShopper (recommended): Called during authorisation to retrieve shopper data for the transaction payload.
  • onGetShippingAddress (optional): Called during authorisation when you need shipping address data included in the transaction.

These callbacks ensure the Paze component always uses the latest customer data from your application state, forms, or APIs when submitting payments.

onGetShopper

This callback is recommended for most integrations. The SDK calls it optionally when building the transaction request, after decryption and before Unity authorisation.

You can use it to:

  • Provide a stable shopper ID for your customer account or guest session.
  • Return the latest name, email, and contact details from your application.
  • Associate the Paze network-token transaction with your customer records.

Configuration

Set onGetShopper on PxpCheckout.initialize():

const pxpSdk = PxpCheckout.initialize({
  environment: 'test',
  session: { /* ... */ },
  transactionData: { /* ... */ },
  onGetShopper: async () => ({
    id: 'shopper-123',
    email: 'customer@example.com',
    firstName: 'John',
    lastName: 'Doe'
  })
});

Event data

This callback receives no parameters. It must return a Promise<Shopper>.

Return value

PropertyDescription
id
string
A unique shopper identifier. Use your customer account ID for logged-in users or a persistent session ID for guest checkout so transactions can be linked to your records.
firstName
string
The shopper's given name, included in the transaction shopper profile sent to Unity.
lastName
string
The shopper's family name, included in the transaction shopper profile sent to Unity.
email
string
The shopper's email address for transaction records and customer correspondence.
phoneNumber
string
A contact phone number for the shopper profile in the transaction request.
dateOfBirth
string
The shopper's date of birth, when required by your integration or risk screening rules.
houseNumberOrName
string
The first line of the shopper's address, such as a house number or building name, for profile data in the transaction.
street
string
The street name or remaining address line for the shopper's profile data.
city
string
The city or locality associated with the shopper's address.
postalCode
string
The postal or ZIP code for the shopper's address.
countryCode
string
A two-letter ISO 3166-1 alpha-2 country code for the shopper's address (for example, "US").
state
string
The state, province, or region for the shopper's address.
products
object
A key-value metadata object describing products in the order, forwarded with the transaction shopper data.
orderDescription
string
A human-readable description of the order included in the transaction shopper data.

All properties are optional in the type, but you should always return an id so transactions can be linked to your customer records.

Example implementation

onGetShopper: async () => {
  const customer = await getCurrentCustomer();

  if (customer) {
    return {
      id: customer.id,
      email: customer.email,
      firstName: customer.firstName,
      lastName: customer.lastName,
      phoneNumber: customer.phone
    };
  }

  return {
    id: getOrCreateGuestShopperId()
  };
}

Paze wallet identity (emailAddress / phoneNumber on the component) is separate from onGetShopper. Component identity controls Paze presentment and checkout. onGetShopper supplies the shopper object sent to Unity during authorisation. When both emailAddress and phoneNumber are set on the component, only phoneNumber is sent to Paze checkout() (both are still used for dynamic canCheckout()).

onGetShippingAddress

This callback is optional. When configured, the SDK calls it during authorisation and includes the returned address in the transaction request.

You can use it to:

  • Include shipping address data for physical goods.
  • Pass fulfilment address details required by your backend or risk screening.

Configuration

Set onGetShippingAddress on PxpCheckout.initialize() alongside onGetShopper:

const pxpSdk = PxpCheckout.initialize({
  // ... session and transactionData
  onGetShopper: async () => ({ id: 'shopper-123' }),
  onGetShippingAddress: async () => ({
    address: '123 Main St',
    city: 'New York',
    state: 'NY',
    postalCode: '10001',
    countryCode: 'US'
  })
});

Event data

This callback receives no parameters. It must return a Promise<ShippingAddress>.

Return value

PropertyDescription
address
string
The primary shipping street address. The SDK maps this value to addressLine1 in the transaction request.
addressLine2
string
An additional shipping address detail, such as an apartment, suite, or unit number.
city
string
The city or locality where the order will be delivered.
state
string
The state, province, or region for the shipping destination.
county
string
The county or district for the shipping destination, when applicable.
postalCode
string
The postal or ZIP code for the shipping destination.
countryCode
string
A two-letter ISO 3166-1 alpha-2 country code for the shipping destination (for example, "US").

Example implementation

onGetShippingAddress: async () => {
  const shipping = await getSelectedShippingAddress();

  return {
    address: shipping.line1,
    addressLine2: shipping.line2,
    city: shipping.city,
    state: shipping.state,
    postalCode: shipping.postalCode,
    countryCode: shipping.countryCode
  };
}

Paze-specific events

Configure these callbacks on pxpSdk.create('paze-button', { ... }). All Paze-specific events are optional and can be mixed and matched based on your business needs.

Callback order

For a successful payment, callbacks fire in this order:

  1. onInit: after the Paze SDK initialises (before presentment resolves in dynamic mode).
  2. onPresentmentResolved: after the button visibility is determined.
  3. onCustomValidationonPazeButtonClicked: when the customer clicks the button.
  4. onCheckoutComplete or onCheckoutIncomplete: after the Paze checkout() popup closes.
  5. onComplete: after Paze complete() returns and the response is decoded.
  6. onPreDecryptiononPostDecryption (if SDK decryption proceeds): decrypt secured payload.
  7. onPreAuthorisation → Unity authorisation (the SDK calls onGetShopper and onGetShippingAddress here) → onPostAuthorisation (if configured).

onError handles init, load, checkout, complete, and decryption errors. onSubmitError handles authorisation submission failures.

SDK initialisation callbacks (onGetShopper, onGetShippingAddress) are configured on PxpCheckout.initialize(). Paze component callbacks handle wallet popup interactions, decryption, and authorisation events.

onInit

This callback is triggered after the Paze SDK initialises for this component, before presentment resolves in dynamic mode.

You can use it to:

  • Log that Paze has successfully initialised.
  • Enable UI elements that depend on Paze being ready.
  • Track SDK initialisation in your analytics.

Event data

This callback receives no parameters.

Example implementation

onInit: () => {
  console.log('Paze component initialised successfully');
  
  // Enable the Paze button in UI
  enablePaymentButton('paze');
  
  // Track initialisation in analytics
  trackEvent('paze-initialised', {
    timestamp: new Date().toISOString()
  });
}

onPresentmentResolved

This callback is triggered after presentment resolves, indicating whether the Paze button is visible or hidden based on eligibility checks.

You can use it to:

  • Show or hide alternative payment methods based on Paze availability.
  • Track how often Paze is presented to customers.
  • Adjust page layout when Paze is not available.

Event data

ParameterDescription
isVisible
boolean
Indicates whether the Paze button is visible to the customer.

Example implementation

onPresentmentResolved: (isVisible) => {
  console.log('Paze button visible:', isVisible);
  
  // Track presentment result
  trackEvent('paze-presentment-resolved', {
    isVisible: isVisible,
    timestamp: new Date().toISOString()
  });
  
  if (!isVisible) {
    // Show alternative payment methods
    showAlternativePaymentMethods();
    console.log('Paze not available, showing alternatives');
  } else {
    // Optionally hide other less preferred methods
    prioritisePazeButton();
  }
}

onCustomValidation

This callback is triggered when the customer clicks the Paze button, before the checkout popup opens. It runs before onPazeButtonClicked and before Paze's checkout() is called.

You can use it to:

  • Validate cart state, inventory, or order totals before checkout starts.
  • Enforce terms acceptance or other merchant business rules.
  • Block checkout from opening when prerequisites are not met.

Return true to allow checkout to proceed, or false to prevent the Paze popup from opening.

Event data

This callback receives no parameters.

Return value

Return valueBehaviour
trueCheckout proceeds to onPazeButtonClicked and the Paze popup.
falseCheckout is cancelled. The Paze popup does not open.

Example implementation

onCustomValidation: async () => {
  if (!cartHasItems()) {
    showError('Your cart is empty.');
    return false;
  }

  if (!termsAccepted()) {
    showError('Please accept the terms and conditions.');
    return false;
  }

  const inventoryAvailable = await checkInventoryAvailability();
  if (!inventoryAvailable) {
    showError('Some items are no longer available.');
    return false;
  }

  return true;
}

Use onCustomValidation for merchant-side checks that must pass before the Paze wallet opens. Use onCheckoutComplete to approve or reject checkout data after the shopper finishes in the Paze popup but before complete() runs.

onPazeButtonClicked

This callback is triggered after onCustomValidation passes, before the Paze checkout() popup opens.

You can use it to:

  • Clear UI state or error messages before starting checkout.
  • Show loading indicators.
  • Track button click events for analytics.

Event data

ParameterDescription
event
Event
The native browser click event object.

Example implementation

onPazeButtonClicked: async (event) => {
  console.log('Paze button clicked');
  
  // Show loading state
  setLoading(true);
  clearErrorMessages();
  
  // Track click event
  trackEvent('paze-button-clicked', {
    timestamp: new Date().toISOString(),
    cartValue: getCurrentCartValue()
  });
}

onCheckoutComplete

This callback is triggered after the Paze popup returns a COMPLETE status, before the SDK calls Paze complete().

You can use it to:

  • Validate the checkout result on your backend.
  • Perform business rule checks before proceeding.
  • Confirm order details with the customer.
  • Apply final price adjustments.

If you omit this callback, the SDK treats checkout as approved and proceeds to complete(), decryption, and authorisation.

Return true to allow the SDK to proceed with complete(), decryption, and transaction submission. Return false to cancel the flow; the SDK then calls onCheckoutIncomplete with reason "Merchant validation rejected completion.".

Event data

ParameterDescription
result
PazeCheckoutResult
Object containing checkout result data.
result.result
string
The checkout result status ("COMPLETE" or "INCOMPLETE").
result.checkoutResponse
string
Present when result is "COMPLETE". Encoded checkout response JWT.
result.checkoutDecodedResponse
object
Present when result is "COMPLETE". Decoded checkout response containing consumer, session, and masked card data.
result.reason
string
Optional reason from Paze (may be present on "COMPLETE" or "INCOMPLETE").

Example implementation

onCheckoutComplete: async (result) => {
  console.log('Paze checkout completed:', result);
  
  try {
    // Validate the checkout result on your backend
    const isValid = await validateCheckoutResult({
      sessionId: result.checkoutDecodedResponse.sessionId,
      consumerEmail: result.checkoutDecodedResponse.consumer.emailAddress,
      cardLast4: result.checkoutDecodedResponse.maskedCard.panLastFour
    });
    
    if (!isValid) {
      showError('Unable to validate checkout. Please try again.');
      return false;
    }
    
    // Check if customer is eligible for this payment method
    const isEligible = await checkCustomerEligibility(
      result.checkoutDecodedResponse.consumer.emailAddress
    );
    
    if (!isEligible) {
      showError('This payment method is not available for your account.');
      return false;
    }
    
    // Track successful checkout completion
    trackEvent('paze-checkout-completed', {
      sessionId: result.checkoutDecodedResponse.sessionId,
      timestamp: new Date().toISOString()
    });
    
    // Proceed with decryption and submission
    return true;
    
  } catch (error) {
    console.error('Checkout validation failed:', error);
    showError('Unable to process payment. Please try again.');
    return false;
  }
}

onCheckoutIncomplete

This callback is triggered when the Paze checkout ends without completion or when the popup is closed by the customer.

You can use it to:

  • Track abandonment rates for conversion optimisation.
  • Show helpful messages or alternative options.
  • Save the customer's cart for later completion.
  • Trigger email campaigns for abandoned checkouts.

Event data

ParameterDescription
result
PazeCheckoutResult
Object containing checkout result data.
result.result
string
The checkout result status ("INCOMPLETE").
result.reason
string
The reason for the incomplete checkout.

Example implementation

onCheckoutIncomplete: (result) => {
  console.log('Paze checkout incomplete:', result);
  
  // Track abandonment for analytics
  trackEvent('paze-checkout-abandoned', {
    reason: result.reason || 'unknown',
    timestamp: new Date().toISOString(),
    cartValue: getCurrentCartValue()
  });
  
  // Preserve cart for later
  saveCartForLater();
  
  // Show context-appropriate message
  // reason values come from Paze or the SDK (e.g. "Merchant validation rejected completion.")
  if (result.reason?.toLowerCase().includes('cancel')) {
    showMessage('No worries! Your items are saved. You can complete your purchase anytime.', 'info');
  } else {
    showMessage('Checkout was not completed. Please try again or use a different payment method.', 'warning');
  }
  
  // Offer alternatives after a short delay
  setTimeout(() => {
    showAlternativePaymentOptions();
  }, 2000);
  
  // Remove loading state
  setLoading(false);
}

onComplete

This callback is triggered when Paze complete() returns successfully and the response JWT is decoded. It runs before onPreDecryption and before any SDK decryption or authorisation.

You can use it to:

  • Read securedPayload from the decoded complete response.
  • Update UI with completion status.
  • Track that the Paze complete step succeeded in analytics.

If onPreDecryption returns false, handle decryption manually using result.completeDecodedResponse.securedPayload. See Backend decryption for the PXP decrypt-token API.

Event data

ParameterDescription
result
PazeCompleteResult
Object containing the complete response data.
result.completeResponse
string
The encoded complete response JWT.
result.completeDecodedResponse
object
The decoded response containing payloadId, sessionId, and securedPayload.
result.completeDecodedResponse.securedPayload
string
The JWE encrypted payload to be decrypted.

Example implementation

onComplete: async (result) => {
  console.log('Paze complete flow finished');
  console.log('Payload ID:', result.completeDecodedResponse?.payloadId);
  console.log('Session ID:', result.completeDecodedResponse?.sessionId);
  
  // Track completion
  trackEvent('paze-complete-flow-finished', {
    payloadId: result.completeDecodedResponse?.payloadId,
    sessionId: result.completeDecodedResponse?.sessionId,
    timestamp: new Date().toISOString()
  });
  
  // If handling decryption manually (when onPreDecryption returns false)
  // Use result.completeDecodedResponse?.securedPayload on your backend
}

onPreDecryption

This callback is triggered after onComplete, before the SDK calls Unity to decrypt the secured payload.

You can use it to:

  • Request merchant operator approval for high-value transactions.
  • Perform additional security checks.
  • Control whether decryption should proceed.
  • Handle decryption manually on your backend.

Return true to allow the SDK to decrypt and continue the built-in flow. Return false to abort SDK decryption and handle it yourself.

Event data

This callback receives no parameters.

Example implementation

To allow SDK to handle decryption:

onPreDecryption: async () => {
  console.log('Pre-decryption check');
  
  // Optional: Check transaction amount or other criteria
  const cartValue = getCurrentCartValue();
  
  if (cartValue > 1000) {
    // Request approval for high-value transactions
    const approved = await requestManagerApproval({
      amount: cartValue,
      timestamp: new Date().toISOString()
    });
    
    if (!approved) {
      showError('Transaction requires manager approval');
      return false;
    }
  }
  
  // Allow SDK to proceed with decryption
  return true;
}

To handle decryption manually:

onPreDecryption: async () => {
  console.log('Preventing SDK decryption - will handle manually');
  
  // Return false to prevent SDK from decrypting
  // Handle decryption in onComplete callback instead
  return false;
}

onPostDecryption

This callback is triggered after Unity successfully decrypts the network token.

You can use it to:

  • Log masked token details for debugging.
  • Store card information for display purposes.
  • Update UI with payment method details.
  • Validate decrypted token before proceeding.

This callback is only triggered if onPreDecryption returns true (SDK-managed decryption).

Event data

ParameterDescription
decryptedPayload
PazeDecryptTokenResponse
The decrypted token response from Unity.
decryptedPayload.shopper
object
Customer information (name, email, phone, country, language).
decryptedPayload.billingAddress
object
Optional billing address (address line, city, state, country code, postal code).
decryptedPayload.fundingData
object
Network token data (token, expiry, account reference, card network, token usage type, dynamic data expiration).

Example implementation

onPostDecryption: async (decryptedPayload) => {
  console.log('Token decrypted successfully');
  
  // Log masked token for debugging (first 6 and last 4 digits only)
  const maskedToken = decryptedPayload.fundingData.networkToken.slice(0, 6) + 
                      '...' + 
                      decryptedPayload.fundingData.networkToken.slice(-4);
  console.log('Masked network token:', maskedToken);
  console.log('Card network:', decryptedPayload.fundingData.cardNetwork);
  console.log('Expiry:', `${decryptedPayload.fundingData.expirationMonth}/${decryptedPayload.fundingData.expirationYear}`);
  
  // Store masked card details for display
  saveMaskedCardDetails({
    network: decryptedPayload.fundingData.cardNetwork,
    lastFour: decryptedPayload.fundingData.networkToken.slice(-4),
    expiry: `${decryptedPayload.fundingData.expirationMonth}/${decryptedPayload.fundingData.expirationYear}`
  });
  
  // Update UI with shopper information
  displayShopperInfo({
    name: decryptedPayload.shopper.fullName,
    email: decryptedPayload.shopper.emailAddress,
    postalCode: decryptedPayload.billingAddress?.postalCode
  });
  
  // Track successful decryption
  trackEvent('paze-decryption-completed', {
    cardNetwork: decryptedPayload.fundingData.cardNetwork,
    timestamp: new Date().toISOString()
  });
}

onPreAuthorisation

This callback is triggered before the transaction is submitted to Unity.

You can use it to:

  • Integrate with Kount or other fraud detection services.
  • Perform AVS (Address Verification System) checks.
  • Apply business rules based on transaction amount or customer history.
  • Include additional risk screening data.
  • Abort the transaction if needed.

Return false to abort the transaction. Return true or null to proceed without extra data. Return a PazeTransactionInitData object with riskScreeningData to include fraud detection data in the transaction request.

Event data

This callback receives no parameters.

Example implementation

To proceed with basic authorisation:

onPreAuthorisation: async () => {
  console.log('Pre-authorisation check');
  
  // Perform basic checks
  const isValid = await validateOrderDetails();
  
  if (!isValid) {
    showError('Order validation failed');
    return false; // Abort transaction
  }
  
  // Proceed with authorisation
  return true;
}

To include risk screening data:

onPreAuthorisation: async () => {
  console.log('Including risk screening data');
  
  const customerData = await getCustomerData();
  const orderItems = await getOrderItems();
  const shippingAddress = await getShippingAddress();
  
  return {
    riskScreeningData: {
      performRiskScreening: true,
      userIp: await getUserIpAddress(),
      account: {
        id: customerData.id,
        creationDateTime: customerData.createdAt
      },
      items: orderItems.map(item => ({
        price: item.price,
        quantity: item.quantity,
        category: item.category,
        sku: item.sku
      })),
      fulfillments: [{
        type: "Shipped",
        shipping: {
          shippingMethod: "Standard"
        },
        recipientPerson: {
          phoneNumber: customerData.phone,
          email: customerData.email,
          address: {
            line1: shippingAddress.street,
            city: shippingAddress.city,
            region: shippingAddress.state,
            countryCode: shippingAddress.countryCode,
            postalCode: shippingAddress.postalCode
          }
        }
      }],
      transaction: {
        subtotal: orderItems.reduce((sum, item) => sum + (item.price * item.quantity), 0)
      }
    }
  };
}

onPostAuthorisation

This callback is triggered after Unity returns a successful HTTP response for the transaction submission. Configure it on the component to receive transaction results; if omitted, the SDK does not call it.

The callback receives authorised, declined, and other non-failure states. HTTP or validation failures route to onSubmitError instead.

You can use it to:

  • Retrieve full authorisation result from your backend using the transaction identifiers.
  • Redirect customers to a success page with order confirmation.
  • Update stock levels for purchased items.
  • Send order confirmation emails to customers.
  • Record successful transactions for business intelligence.

Event data

ParameterDescription
data
PazePostAuthorisationData
Object containing transaction result data.
data.merchantTransactionId
string
Your unique identifier for the transaction.
data.systemTransactionId
string
The Unity system transaction identifier.
data.networkToken
string
The network token used for the transaction.
data.providerResponseCode
string
Optional provider response code.
data.state
string
Optional transaction state (e.g. "Authorised", "Declined", "Error").
data.stateDataCode
string
Optional additional state information code.

Example implementation

onPostAuthorisation: async (data) => {
  console.log('Payment authorisation completed');
  console.log('Merchant Transaction ID:', data.merchantTransactionId);
  console.log('System Transaction ID:', data.systemTransactionId);
  console.log('Transaction State:', data.state);
  
  try {
    // Retrieve full transaction details from your backend
    const transactionResult = await getTransactionResult(
      data.merchantTransactionId,
      data.systemTransactionId
    );
    
    if (data.state === 'Authorised') {
      // Update inventory
      await updateInventory(data.merchantTransactionId);
      
      // Send confirmation email
      await sendOrderConfirmation({
        transactionId: data.merchantTransactionId,
        systemTransactionId: data.systemTransactionId,
        amount: transactionResult.amount
      });
      
      // Track successful purchase
      trackEvent('paze-purchase-completed', {
        transactionId: data.merchantTransactionId,
        amount: transactionResult.amount,
        timestamp: new Date().toISOString()
      });
      
      // Redirect to success page
      window.location.href = `/payment-success?txn=${data.merchantTransactionId}`;
      
    } else if (data.state === 'Declined') {
      console.error('Payment declined:', data.providerResponseCode);
      showErrorMessage('Payment declined. Please try again or use a different payment method.');
      setLoading(false);
      
    } else {
      console.error('Unexpected payment state:', data.state);
      showErrorMessage('Payment processing error. Please contact support if charged.');
      setLoading(false);
    }
    
  } catch (error) {
    console.error('Failed to process post-authorisation:', error);
    showErrorMessage('Unable to confirm payment status. Please contact support.');
    setLoading(false);
  }
}

onSubmitError

This callback is triggered when transaction submission or pre-submit validation fails.

You can use it to:

  • Log errors for debugging and support.
  • Display user-friendly error messages.
  • Offer alternative payment methods.
  • Report errors to your monitoring system.

Event data

The callback receives one of:

TypeWhenKey fields
FailedSubmitResultRisk screening validation fails before submit, or Unity returns an HTTP error responseerrorCode, errorReason, correlationId, httpStatusCode, details
PazeTransactionFailedExceptionUnity returns a failed transaction responseErrorCode, message, submitResult (FailedSubmitResult)
BaseSdkExceptionOther authorisation errorsErrorCode, message, details

Example implementation

onSubmitError: async (submitError) => {
  console.error('Transaction submission failed:', submitError);

  // PazeTransactionFailedException wraps FailedSubmitResult
  if ('submitResult' in submitError) {
    const failed = submitError.submitResult;
    logErrorToMonitoring({
      errorCode: failed.errorCode,
      errorReason: failed.errorReason,
      correlationId: failed.correlationId,
      httpStatusCode: failed.httpStatusCode
    });
    showSupportInfo(`Reference: ${failed.correlationId}`);
    showErrorMessage('Payment failed. Please try again.');
    return;
  }

  // FailedSubmitResult (e.g. risk screening validation)
  if ('errorCode' in submitError && 'errorReason' in submitError) {
    showErrorMessage(submitError.errorReason);
    return;
  }

  // BaseSdkException
  showErrorMessage(submitError.message);
  logErrorToMonitoring({
    errorCode: submitError.ErrorCode,
    message: submitError.message
  });

  setLoading(false);
}

onError

This callback is triggered when SDK, presentment, checkout, complete, or decryption errors occur (initialisation, script load, popup failures, and similar).

You can use it to:

  • Log errors for debugging and monitoring.
  • Display user-friendly error messages.
  • Offer alternative payment methods.
  • Report critical errors to support.

Event data

ParameterDescription
error
BaseSdkException
The error object containing details.
error.ErrorCode
string
The SDK error code.
error.message
string
Human-readable error description.
error.details
any
Additional error details (optional).

Example implementation

onError: (error) => {
  console.error('Paze SDK error:', error);
  
  // Log error for debugging
  logError('paze-sdk-error', {
    errorCode: error.ErrorCode,
    message: error.message,
    details: error.details,
    timestamp: new Date().toISOString()
  });
  
  // Handle different error types
  let userMessage = 'Payment setup failed. Please try again.';
  
  if (error.message.includes('initialization') || error.message.includes('initialisation')) {
    userMessage = 'Unable to initialise payment method. Please refresh the page.';
    notifySupport('Paze initialization failed', error);
  } else if (error.message.includes('Network') || error.message.includes('timeout')) {
    userMessage = 'Network error. Please check your connection and try again.';
  } else if (error.message.includes('popup') || error.message.includes('blocked')) {
    userMessage = 'Popup was blocked. Please allow popups for this site and try again.';
  } else if (error.message.includes('configuration')) {
    userMessage = 'Payment system configuration error. Please contact support.';
    notifySupport('Paze configuration error', error);
  }
  
  showErrorMessage(userMessage);
  
  // Track error in analytics
  trackEvent('paze-error', {
    errorCode: error.ErrorCode,
    errorType: error.message,
    timestamp: new Date().toISOString()
  });
  
  // Show alternative payment options
  showAlternativePaymentMethods();
}

Event data structures

Shopper

The object returned by onGetShopper:

interface Shopper {
  id?: string;
  firstName?: string;
  lastName?: string;
  dateOfBirth?: string;
  email?: string;
  phoneNumber?: string;
  houseNumberOrName?: string;
  street?: string;
  city?: string;
  postalCode?: string;
  countryCode?: string;
  state?: string;
  products?: Record<string, string>;
  orderDescription?: string;
}

ShippingAddress

The object returned by onGetShippingAddress:

interface ShippingAddress {
  countryCode?: string;
  postalCode?: string;
  address?: string;
  addressLine2?: string;
  city?: string;
  county?: string;
  state?: string;
}

PazeCheckoutResult

The checkout result object passed to onCheckoutComplete and onCheckoutIncomplete:

interface PazeCheckoutResult {
  result: "COMPLETE" | "INCOMPLETE";
  checkoutResponse?: string;
  reason?: string;
  checkoutDecodedResponse?: {
    sessionId?: string;
    consumer: {
      fullName: string;
      firstName: string;
      lastName: string;
      emailAddress: string;
      mobileNumber: PazePhoneNumber | null;
      countryCode: string;
      languageCode: string;
    };
    maskedCard: {
      digitalCardId: string;
      panLastFour: string;
      paymentAccountReference: string;
      panExpirationMonth: string;
      panExpirationYear: string;
      paymentCardDescriptor: string;
      paymentCardType: string;
      paymentCardBrand: string;
      paymentCardNetwork: string;
      digitalCardData: PazeDigitalCardData;
      billingAddress: PazeCheckoutAddress;
    };
  };
}

checkoutDecodedResponse is only populated when result is "COMPLETE".

PazeCompleteResult

The complete result object passed to onComplete:

interface PazeCompleteResult {
  completeResponse: string;
  completeDecodedResponse?: {
    payloadId: string;
    sessionId?: string;
    securedPayload?: string;
  };
}

decryptedPayload is not populated on onComplete. Decrypted token data is passed to onPostDecryption when SDK decryption proceeds.

PazeDecryptTokenResponse

The decrypted token response passed to onPostDecryption:

interface PazeDecryptTokenResponse {
  shopper: {
    firstName?: string;
    lastName?: string;
    fullName: string;
    emailAddress: string;
    phoneCountryCode?: string;
    phoneNumber?: string;
    countryCode?: string;
    languageCode?: string;
  };
  billingAddress?: {
    addressLine1: string;
    city: string;
    state: string;
    countryCode: string;
    postalCode: string;
  };
  fundingData: {
    networkToken: string;
    expirationMonth: string;
    expirationYear: string;
    accountReference?: string;
    cardNetwork: string;
    tokenUsageType?: string;
    dynamicDataExpiration?: string;
  };
}

PazePostAuthorisationData

The authorisation data passed to onPostAuthorisation:

interface PazePostAuthorisationData {
  merchantTransactionId: string;
  systemTransactionId: string;
  networkToken: string;
  providerResponseCode?: string;
  state?: string;
  stateDataCode?: string;
}

onSubmitError payload types

onSubmitError may receive FailedSubmitResult, PazeTransactionFailedException (with a submitResult property), or BaseSdkException. See the onSubmitError section above.

FailedSubmitResult

Used for HTTP submission failures and validation errors before submit:

interface FailedSubmitResult {
  errorCode: string;
  errorReason: string;
  correlationId: string;
  httpStatusCode: number;
  details: any[];
}

BaseSdkException

The error data passed to onError:

interface BaseSdkException {
  ErrorCode: string;
  message: string;
  details?: any;
}

Error handling in events

Event callbacks should handle errors gracefully and provide appropriate feedback to customers:

const pazeConfig = {
  onCheckoutComplete: async (result) => {
    try {
      // Validate checkout result
      const isValid = await validateCheckout(result);
      
      if (!isValid) {
        showError('Checkout validation failed');
        return false;
      }
      
      return true;
      
    } catch (error) {
      console.error('Checkout validation error:', error);
      showError('Unable to validate checkout. Please try again.');
      return false;
    }
  },
  
  onPostAuthorisation: async (data) => {
    try {
      // Retrieve transaction details from backend
      const result = await getTransactionResult(
        data.merchantTransactionId,
        data.systemTransactionId
      );
      
      if (data.state === 'Authorised') {
        // Process successful payment
        await processSuccessfulPayment(data);
        window.location.href = `/payment-success?txn=${data.merchantTransactionId}`;
      } else {
        showErrorMessage('Payment was not authorised. Please try again.');
      }
      
    } catch (error) {
      console.error('Failed to retrieve transaction result:', error);
      showErrorMessage('Unable to confirm payment status. Please contact support.');
    }
  },
  
  onSubmitError: async (submitError) => {
    console.error('Transaction submission failed:', submitError);

    if ('submitResult' in submitError) {
      showErrorMessage(submitError.submitResult.errorReason);
    } else if ('errorCode' in submitError) {
      showErrorMessage(submitError.errorReason);
    } else {
      showErrorMessage(submitError.message);
    }

    setLoading(false);
  },
  
  onError: (error) => {
    console.error('Paze SDK error:', error);
    
    // Log for debugging
    logError('paze-error', error);
    
    // Show appropriate message
    if (error.message.includes('popup')) {
      showErrorMessage('Please allow popups for this site and try again.');
    } else if (error.message.includes('initialization')) {
      showErrorMessage('Unable to initialise payment method. Please refresh the page.');
    } else {
      showErrorMessage('Payment setup failed. Please try again or use a different payment method.');
    }
  }
};

Advanced event usage

Handling decryption manually

If you need to decrypt the secured payload on your own backend instead of using the SDK's built-in decryption, see Backend decryption for the PXP decrypt-token API.

const pazeConfig = {
  // Prevent SDK from decrypting
  onPreDecryption: async () => {
    console.log('Handling decryption manually');
    return false;
  },
  
  // Handle secured payload in onComplete
  onComplete: async (result) => {
    const securedPayload = result.completeDecodedResponse?.securedPayload;
    
    try {
      // Forward securedPayload to your backend (never decrypt in the browser)
      const decryptedData = await fetch('/api/paze/decrypt', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ securedPayload })
      }).then(r => r.json());
      
      // Use decrypted data to submit transaction
      const transactionResult = await submitTransaction(decryptedData);
      
      if (transactionResult.success) {
        window.location.href = `/payment-success?txn=${transactionResult.transactionId}`;
      } else {
        showErrorMessage('Transaction failed. Please try again.');
      }
      
    } catch (error) {
      console.error('Manual decryption failed:', error);
      showErrorMessage('Payment processing failed. Please try again.');
    }
  }
};

Fraud detection integration

Integrate with fraud detection services in the onPreAuthorisation callback:

onPreAuthorisation: async () => {
  console.log('Performing fraud checks');
  
  try {
    const customerData = await getCustomerData();
    const orderData = await getOrderData();
    const shippingAddress = await getShippingAddress();
    
    // Optional merchant-side fraud check before submit
    const fraudScore = await checkFraudScore({
      customerId: customerData.id,
      orderValue: orderData.total
    });
    
    if (fraudScore > 70) {
      showErrorMessage('We were unable to process your payment. Please contact support.');
      return false;
    }
    
    return {
      riskScreeningData: {
        performRiskScreening: true,
        userIp: await getUserIpAddress(),
        account: {
          id: customerData.id,
          creationDateTime: customerData.createdAt
        },
        items: orderData.items.map(item => ({
          price: item.price,
          quantity: item.quantity,
          category: item.category,
          sku: item.sku
        })),
        fulfillments: [{
          type: 'Shipped',
          shipping: {
            shippingMethod: orderData.shippingMethod
          },
          recipientPerson: {
            name: {
              first: customerData.firstName,
              family: customerData.lastName
            },
            email: customerData.email,
            phoneNumber: customerData.phone,
            address: {
              line1: shippingAddress.street,
              city: shippingAddress.city,
              region: shippingAddress.state,
              countryCode: shippingAddress.countryCode,
              postalCode: shippingAddress.postalCode
            }
          }
        }],
        transaction: {
          subtotal: orderData.subtotal
        }
      }
    };
    
  } catch (error) {
    console.error('Fraud check failed:', error);
    logError('fraud-check-failed', error);
    return true;
  }
}

Analytics tracking

Track Paze events comprehensively for business intelligence:

const pazeConfig = {
  onInit: () => {
    trackEvent('paze_initialized', {
      timestamp: new Date().toISOString()
    });
  },
  
  onPresentmentResolved: (isVisible) => {
    trackEvent('paze_presentment_resolved', {
      is_visible: isVisible,
      timestamp: new Date().toISOString()
    });
  },

  onCustomValidation: async () => {
    return cartHasItems() && termsAccepted();
  },
  
  onPazeButtonClicked: async (event) => {
    trackEvent('paze_button_clicked', {
      cart_value: getCurrentCartValue(),
      cart_items: getCartItemCount(),
      timestamp: new Date().toISOString()
    });
  },
  
  onCheckoutComplete: async (result) => {
    trackEvent('paze_checkout_completed', {
      session_id: result.checkoutDecodedResponse.sessionId,
      card_network: result.checkoutDecodedResponse.maskedCard.paymentCardNetwork,
      timestamp: new Date().toISOString()
    });
    return true;
  },
  
  onCheckoutIncomplete: (result) => {
    trackEvent('paze_checkout_abandoned', {
      reason: result.reason,
      cart_value: getCurrentCartValue(),
      timestamp: new Date().toISOString()
    });
  },
  
  onPostAuthorisation: async (data) => {
    trackEvent('paze_payment_completed', {
      merchant_transaction_id: data.merchantTransactionId,
      system_transaction_id: data.systemTransactionId,
      state: data.state,
      timestamp: new Date().toISOString()
    });
    
    // Process payment...
  },
  
  onSubmitError: async (submitError) => {
    const errorCode = 'submitResult' in submitError
      ? submitError.submitResult.errorCode
      : 'errorCode' in submitError
        ? submitError.errorCode
        : submitError.ErrorCode;

    trackEvent('paze_payment_failed', {
      error_code: errorCode,
      timestamp: new Date().toISOString()
    });
  }
};