Learn how to test your Paze integration effectively before going live.
Thorough testing is essential to ensure your Paze integration works correctly across presentment modes, checkout flows, and error scenarios. This guide covers test environments, configuration, test scenarios, and debugging techniques.
Always test your integration in the UAT environment before deploying to production. Use test credentials and the Paze UAT SDK to avoid processing real payments during development.
Initialise the SDK with test environment settings, USD transaction data, and a test shopper callback:
import { PxpCheckout, IntentType } from '@pxpio/web-components-sdk';
const pxpSdk = PxpCheckout.initialize({
environment: 'test', // Use 'test' for UAT
session: sessionData, // From your backend
ownerId: 'your-owner-id',
ownerType: 'MerchantGroup',
clientName: 'Your Merchant',
siteName: 'Your Store',
kountDisabled: true, // Disable Kount during initial testing
transactionData: {
currency: 'USD',
amount: 10.00,
merchantTransactionId: crypto.randomUUID(),
merchantTransactionDate: () => new Date().toISOString(),
entryType: 'Ecom',
intent: {
card: IntentType.Authorisation
}
},
onGetShopper: () => Promise.resolve({
id: 'test-shopper-1',
email: 'test@example.com',
firstName: 'Test',
lastName: 'Shopper'
})
});| Environment | Paze SDK URL | Purpose |
|---|---|---|
test | checkout.wallet.uat.earlywarning.io | Development and UAT testing |
live | checkout.paze.com | Production payments |
Never use production Paze credentials in development. UAT and live environments use separate client IDs and SDK endpoints.
Dynamic presentment (buttonRenderMode: "dynamic") calls Paze canCheckout() with the shopper's emailAddress and phoneNumber. The button stays hidden when Paze reports no eligible wallet (onPresentmentResolved(false)).
To test dynamic mode in UAT:
- Use UAT credentials end-to-end: Portal Paze client ID on your site,
environment: 'test'in the SDK, and the UAT Paze SDK URL (loaded automatically whenenvironmentistest). - Register test shoppers with Paze: Use email and phone combinations that Paze has provisioned for your UAT merchant account. Paze provides eligible test identities during merchant onboarding — contact your Paze integration contact if you do not have UAT shopper credentials.
- Match identity at checkout: If both email and phone are set, only
phoneNumberis sent to Pazecheckout(). Use the same phone number Paze registered for the test wallet. - Start with static mode: Use
buttonRenderMode: 'static'while validating session, decrypt, and transaction flows before testing eligibility gating.
Static mode does not call canCheckout(). It shows the button after successful SDK initialisation, which is useful for testing checkout and payment flows before you have UAT-eligible shopper identities.
Create a Paze button with logging callbacks on each stage of the payment flow:
const TEST_CONFIG = {
environment: 'test' as const,
emailAddress: 'test.shopper@example.com',
phoneNumber: '15551234567',
amount: 10.00,
currency: 'USD'
};
const pazeButton = pxpSdk.create('paze-button', {
buttonRenderMode: 'static',
emailAddress: TEST_CONFIG.emailAddress,
phoneNumber: TEST_CONFIG.phoneNumber,
style: {
color: 'pazeblue',
shape: 'pill',
label: 'check out with'
},
onInit: () => console.log('TEST: Paze initialised'),
onPresentmentResolved: (isVisible) => console.log('TEST: Button visible:', isVisible),
onPazeButtonClicked: () => console.log('TEST: Button clicked'),
onCheckoutComplete: async (result) => {
console.log('TEST: Checkout complete:', result);
return true; // Approve to continue
},
onComplete: async (result) => {
// Fires after Paze complete() decodes the response, before decryption
console.log('TEST: Complete result:', result.completeDecodedResponse?.payloadId);
},
onPostDecryption: async (payload) => {
console.log('TEST: Decrypted token:', payload.fundingData?.cardNetwork);
},
onPostAuthorisation: async (data) => {
console.log('TEST: Authorisation result:', data.systemTransactionId);
},
onError: (error) => {
console.error('TEST: Error:', error.ErrorCode, error.message);
}
});
pazeButton.mount('paze-button-container');In static mode, the button renders after successful initialisation and onPresentmentResolved(true) fires. This does not call canCheckout() to verify wallet eligibility:
const pazeButton = pxpSdk.create('paze-button', {
buttonRenderMode: 'static',
onPresentmentResolved: (isVisible) => {
console.log('Static presentment resolved:', isVisible);
// true after successful init and render; not called when initialisation fails (check onError)
}
});
pazeButton.mount('paze-button-container');In dynamic mode, the SDK calls canCheckout() and hides the button when the shopper has no eligible Paze wallet:
const pazeButton = pxpSdk.create('paze-button', {
buttonRenderMode: 'dynamic',
emailAddress: 'eligible.shopper@example.com',
phoneNumber: '15551234567',
onPresentmentResolved: (isVisible) => {
console.log('Dynamic presentment result:', isVisible);
// isVisible is false when canCheckout() reports no eligible wallet
}
});
pazeButton.mount('paze-button-container');Return true from onCheckoutComplete to exercise the full happy path through complete(), decryption, and authorisation:
onCheckoutComplete: async (result) => {
console.log('Checkout data:', {
sessionId: result.checkoutDecodedResponse?.sessionId,
consumerEmail: result.checkoutDecodedResponse?.consumer?.emailAddress,
cardNetwork: result.checkoutDecodedResponse?.maskedCard?.paymentCardNetwork,
panLastFour: result.checkoutDecodedResponse?.maskedCard?.panLastFour
});
return true;
}Return false from onCheckoutComplete to confirm the SDK treats checkout as incomplete:
onCheckoutComplete: async (result) => {
console.log('Rejecting checkout for testing');
return false;
},
onCheckoutIncomplete: async (result) => {
console.log('Expected incomplete result:', result.reason);
// Merchant rejection: "Merchant validation rejected completion."
}Return true from onPreDecryption (or omit the callback) to test the default SDK decryption path:
onPreDecryption: async () => {
console.log('SDK will decrypt automatically');
return true; // or omit callback entirely
},
onPostDecryption: async (payload) => {
console.log('Decrypted network token present:', !!payload.fundingData?.networkToken);
console.log('Card network:', payload.fundingData?.cardNetwork);
}Return false from onPreDecryption and handle securedPayload in onComplete. Your test backend should call the PXP decrypt-token API — see Backend decryption:
onPreDecryption: async () => false,
onComplete: async (result) => {
const securedPayload = result.completeDecodedResponse?.securedPayload;
console.log('Secured payload received:', !!securedPayload);
// Send to your test backend
const response = await fetch('/api/paze/decrypt', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ securedPayload })
});
console.log('Backend decryption result:', await response.json());
}Mount or initialise components to trigger validation errors and confirm the expected SDK error codes:
// Test invalid currency (fails when the component initialises)
const invalidSdk = PxpCheckout.initialize({
...config,
transactionData: { ...config.transactionData, currency: 'GBP' }
});
const invalidCurrencyButton = invalidSdk.create('paze-button', { buttonRenderMode: 'static' });
invalidCurrencyButton.mount('paze-button-container');
// Expected: SDK1213 via onError
// Test missing identity for dynamic mode
const dynamicButton = pxpSdk.create('paze-button', {
buttonRenderMode: 'dynamic',
emailAddress: 'test@example.com'
// Missing phoneNumber — expected: SDK1208 on mount
});
dynamicButton.mount('paze-button-container');
// Test invalid phone format
const invalidPhone = pxpSdk.create('paze-button', {
buttonRenderMode: 'static',
phoneNumber: '+15551234567' // Expected: SDK1212 on mount
});
invalidPhone.mount('paze-button-container');Wrap component callbacks to trace the payment flow during manual or automated testing:
const callbacks = [
'onInit', 'onPresentmentResolved', 'onCustomValidation', 'onPazeButtonClicked',
'onCheckoutComplete', 'onCheckoutIncomplete', 'onComplete',
'onPreDecryption', 'onPostDecryption',
'onPreAuthorisation', 'onPostAuthorisation', 'onSubmitError', 'onError'
];
const logConfig = Object.fromEntries(
callbacks.map(name => [name, (...args: unknown[]) => {
console.log(`[Paze] ${name}:`, ...args);
}])
);
const pazeButton = pxpSdk.create('paze-button', {
...logConfig,
onCheckoutComplete: async (result) => {
console.log('[Paze] onCheckoutComplete:', result);
return true;
}
});
pazeButton.mount('paze-button-container');Log analytics events from PxpCheckout.initialize() to verify the payment funnel. For the full event list, see Analytics:
const pxpSdk = PxpCheckout.initialize({
...config,
analyticsEvent: (event) => {
console.log('Analytics:', event.eventName, event);
}
});Key events to verify during testing:
| Event | When it fires |
|---|---|
PazeButtonRendered | The Paze button became visible |
PazeButtonClicked | The shopper clicked the button |
PazePopupLaunched | The Paze checkout popup opened |
PazeCheckoutCompleted | Checkout returned COMPLETE |
PazeCheckoutAbandoned | Checkout incomplete, popup closed, or merchant rejected checkout |
PazeDecryptionInitiated | SDK decryption started |
PazeDecryptionCompleted | SDK decryption succeeded |
PazeDecryptionFailed | SDK decryption failed |
PazeTransactionInitiated | Transaction submission to PXP started (componentType: 'PazeButton') |
PreAuthorisation | onPreAuthorisation is configured and the flow proceeds (componentType: 'Paze') |
PostAuthorisation | onPostAuthorisation is configured and submission succeeds (componentType: 'Paze') |
PazeAuthorisationFailed | Transaction submission failed |
Wallet visibility is not an analytics event. Track it with onPresentmentResolved instead.
Run these checks in the browser console when the button does not appear:
function diagnosePaze() {
const config = pxpSdk.getConfig();
const session = config.session;
console.group('Paze Diagnostics');
console.log('Environment:', config.environment);
console.log('Currency:', config.transactionData.currency);
console.log('Amount:', config.transactionData.amount);
console.log('Client ID:', session.allowedFundingTypes?.wallets?.paze?.clientId ? 'Present' : 'Missing');
console.log('HTTPS:', location.protocol === 'https:' || location.hostname === 'localhost');
console.log('Paze SDK loaded:', !!window.DIGITAL_WALLET_SDK);
console.groupEnd();
}Before going live, verify each scenario:
- Session includes
allowedFundingTypes.wallets.paze.clientId - Currency is
USD - Amount is greater than 0
-
onGetShopperreturns valid shopper data - HTTPS is enabled (or localhost for development)
- Static mode renders the button after successful initialisation
- Dynamic mode shows the button for eligible shoppers
- Dynamic mode hides the button when
canCheckout()reports no wallet -
onPresentmentResolvedfires with the expected visibility
- Button click opens the Paze checkout popup
- Successful checkout triggers
onCheckoutComplete - Returning
falsefromonCheckoutCompletetriggersonCheckoutIncompletewith"Merchant validation rejected completion." - Shopper closing the popup triggers
onCheckoutIncomplete
- SDK-managed decryption returns token data in
onPostDecryption - Manual decryption receives
securedPayloadinonComplete(beforeonPreDecryptionruns) -
onPreAuthorisationreturningfalsecancels authorisation -
onPostAuthorisationis configured and fires for successful HTTP responses (includingDeclinedstates) - HTTP submission failures fire
onSubmitError
- Invalid configuration surfaces errors via
onError - Network errors are handled gracefully
- Session expiry is handled with user guidance
Before going live with Paze, ensure your implementation meets these requirements:
- HTTPS enabled on all checkout pages (localhost exempt for development).
- Paze client ID configured in Unity Portal for the correct site.
-
environment: 'live'with production Paze credentials. - Transaction currency set to
USD. - Tested on Chrome, Safari, Firefox, and Edge.
- Comprehensive error handling for all payment scenarios.
- Uses official
<paze-button>element with approved style values. - Paze button has equal prominence with other payment methods.
- Button renders correctly on desktop and mobile viewports.
- Dynamic presentment hides the button when shopper is ineligible.
- Valid SSL certificate from a recognised authority.
- No storage of sensitive payment data in browser storage.
- Backend verification of all successful transactions.
- HMAC credentials stored securely on the server only.
- Privacy policy covers payment and identity data usage.
- Clear error messages when Paze is unavailable.
- Graceful fallback to other payment methods.
- Loading indicators during checkout and processing.
- Session refresh handling for expired sessions.
- End-to-end payment testing in UAT environment.
- Tested static and dynamic presentment modes.
- Tested checkout approval and rejection flows.
- Tested SDK-managed and manual decryption paths.
- Tested transaction failure and retry scenarios.