Understand error types, handle payment failures, and implement proper error recovery.
Drop-in provides comprehensive error handling through the onError callback. All payment failures, validation errors, and SDK exceptions are caught and delivered through this unified interface, making error handling consistent across all payment methods.
All errors are delivered through the onError callback:
import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';
import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';
const checkoutDropIn = CheckoutDropIn.initialize({
// ... other config
onError: (error: BaseSdkException) => {
console.error('Payment failed:', error.message);
console.error('Error code:', error.code);
// Handle the error
showErrorMessage(error.message);
}
});| Property | Description |
|---|---|
messagestring | Human-readable error message describing what went wrong. |
ErrorCodestring | SDK error code in format SDK#### (e.g., 'SDK1114' for authentication failed, 'SDK0500' for network error). Use this for programmatic error handling. |
namestring | Exception class name (e.g., 'CheckoutDropInCardPaymentFailedSdkException'). |
Errors are organised into four main categories based on their source and nature.
Errors that occur during SDK initialisation or component rendering due to invalid configuration.
| Exception | Error code | Description | Solution |
|---|---|---|---|
CheckoutDropInConfigNotFoundSdkException | SDK1100 | Drop-in configuration not found or invalid. | Verify initialisation parameters. |
CheckoutDropInFailedToRenderCardSdkException | SDK1101 | Failed to render card component. | Check session configuration for card support. |
CheckoutDropInFailedToRenderPaypalSdkException | SDK1102 | Failed to render PayPal button. | Verify PayPal is enabled in session. |
CheckoutDropInFailedToRenderGooglePaySdkException | SDK1103 | Failed to render Google Pay button. | Check Google Pay configuration. |
CheckoutDropInFailedToRenderApplePaySdkException | SDK1104 | Failed to render Apple Pay button. | Verify Apple Pay domain registration. |
CheckoutDropInInvalidPaypalEntryTypeSdkException | SDK1120 | PayPal only supports Ecom entry type. | Change entryType to 'Ecom'. |
Example handling:
onError: (error: BaseSdkException) => {
if (error.name.includes('FailedToRender')) {
console.error('Payment method rendering failed:', error.message);
// Log to monitoring
logger.error('Rendering error', {
exception: error.name,
errorCode: error.code,
message: error.message
});
// Show generic error to user
showErrorMessage(
'We\'re having trouble loading payment options. Please refresh the page or contact support.'
);
}
}Errors that occur during payment processing for specific payment methods.
| Exception | Error code | Description | User action |
|---|---|---|---|
CheckoutDropInCardPaymentFailedSdkException | SDK1116 | Card payment failed (see detection patterns below). | See card-specific patterns below. |
CheckoutDropInPaypalPaymentFailedSdkException | SDK1117 | PayPal transaction failed. | Try again or use different method. |
CheckoutDropInGooglePayPaymentFailedSdkException | SDK1118 | Google Pay transaction failed. | Try again or use different method. |
CheckoutDropInApplePayPaymentFailedSdkException | SDK1119 | Apple Pay transaction failed. | Try again or use different method. |
Since card errors come from providers with varying message formats, use message-based detection:
| Scenario | Detection approach | User action |
|---|---|---|
| Card declined | error.message contains "declined" | Try a different card or contact bank. |
| Insufficient funds | error.message contains "insufficient funds" | Use a different payment method. |
| Expired card | error.message contains "expired" | Use a different card. |
| Invalid CVV | error.message contains "CVV" or "security code" | Check security code and retry. |
| Invalid card number | error.message contains "card number" or "invalid number" | Check card number and retry. |
| Invalid expiry | error.message contains "expiry" or "expiration" | Check expiry date and retry. |
Example handling:
onError: (error: BaseSdkException) => {
// Card-specific errors (message-based detection)
if (error.code === 'SDK1116') {
// Card payment failed - check message for specifics
if (error.message.toLowerCase().includes('declined')) {
showErrorMessage(
'Your card was declined. Please try a different card or contact your bank for more information.'
);
offerAlternativePaymentMethods();
} else if (error.message.toLowerCase().includes('insufficient funds')) {
showErrorMessage(
'Insufficient funds. Please use a different payment method.'
);
offerAlternativePaymentMethods();
} else if (error.message.toLowerCase().includes('expired')) {
showErrorMessage(
'This card has expired. Please use a different card.'
);
} else if (error.message.toLowerCase().includes('cvv') ||
error.message.toLowerCase().includes('security code')) {
showErrorMessage(
'Invalid security code. Please check the CVV on the back of your card and try again.'
);
// Keep same payment method selected for retry
} else {
showErrorMessage(
'Card payment failed. Please check your details and try again.'
);
}
}
// Wallet payment errors
else if (error.code === 'SDK1117') {
showErrorMessage(
'PayPal payment failed. Please try again or use a different payment method.'
);
offerAlternativePaymentMethods();
} else if (error.code === 'SDK1118') {
showErrorMessage(
'Google Pay payment failed. Please try again or use a different payment method.'
);
offerAlternativePaymentMethods();
} else if (error.code === 'SDK1119') {
showErrorMessage(
'Apple Pay payment failed. Please try again or use a different payment method.'
);
offerAlternativePaymentMethods();
}
}Errors related to 3D Secure (3DS) authentication for card payments.
| Exception | Error code | Description | User action |
|---|---|---|---|
CheckoutDropInAuthenticationFailedSdkException | SDK1114 | 3DS authentication failed. | Try again or use different card. |
Note: Authentication timeout and cancellation are also reported through error.message. Check the message content for these scenarios:
- Timeout:
error.messagecontains "timeout" - Cancelled:
error.messagecontains "cancel"
Example handling:
onError: (error: BaseSdkException) => {
if (error.code === 'SDK1114' || error.message.toLowerCase().includes('authentication')) {
if (error.message.toLowerCase().includes('timeout')) {
showErrorMessage(
'3D Secure authentication timed out. Please check your internet connection and try again.'
);
// Offer retry
showRetryButton();
} else if (error.message.toLowerCase().includes('cancel')) {
showErrorMessage(
'Authentication was cancelled. Please try again to complete your payment.'
);
// Don't show error as prominently - user intentionally cancelled
showInfoMessage('You can retry your payment when ready.');
} else {
showErrorMessage(
'3D Secure authentication failed. Please try again or use a different card.'
);
// Track authentication failures
analytics.track('3ds_authentication_failed', {
timestamp: Date.now()
});
}
}
}Errors that occur during payment authorisation.
| Exception | Error code | Description | Solution |
|---|---|---|---|
CheckoutDropInAuthorisationFailedSdkException | SDK1115 | Payment authorisation failed. | Check transaction details and retry. |
Errors related to network connectivity, session state, and system availability.
| Error code | Detection approach | User action |
|---|---|---|
SDK0500 | Network error code | Check connection and retry. |
| Message-based | error.message contains "session" or "expired" | Refresh page and retry. |
| Message-based | error.message contains "timeout" | Check connection and retry. |
| Message-based | error.message contains "unavailable" or "service" | Try again later. |
SDK01XX or SDK02XX | Configuration error codes (01XX = SDK, 02XX = Component) | Contact support. |
Example handling:
onError: (error: BaseSdkException) => {
// Network and session errors
if (error.code === 'SDK0500') {
showErrorMessage(
'Network connection issue. Please check your internet connection and try again.'
);
showRetryButton();
} else if (error.message.toLowerCase().includes('session') ||
error.message.toLowerCase().includes('expired')) {
showErrorMessage(
'Your payment session has expired. Please refresh the page and try again.'
);
showRefreshButton();
} else if (error.message.toLowerCase().includes('timeout')) {
showErrorMessage(
'Request timed out. Please check your connection and try again.'
);
showRetryButton();
} else if (error.message.toLowerCase().includes('unavailable') ||
error.message.toLowerCase().includes('service')) {
showErrorMessage(
'Payment service is temporarily unavailable. Please try again in a few minutes.'
);
} else if (error.code && (error.code.startsWith('SDK01') ||
error.code.startsWith('SDK02'))) {
showErrorMessage(
'Payment configuration error. Please contact support for assistance.'
);
// Log critical error
logger.critical('Configuration error', {
errorCode: error.code,
message: error.message
});
}
}The simplest error handling pattern shows user-friendly messages and logs errors for debugging.
import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';
const checkoutDropIn = CheckoutDropIn.initialize({
// ... other config
onError: (error: BaseSdkException) => {
// Log error for debugging
console.error('Payment error:', {
errorCode: error.code,
message: error.message,
name: error.name
});
// Show user-friendly message
showErrorNotification(error.message || 'Payment failed. Please try again.');
// Re-enable payment button
enablePaymentButton();
}
});Implement retry logic, alternative payment methods, and error categorisation.
let retryCount = 0;
const MAX_RETRIES = 3;
const checkoutDropIn = CheckoutDropIn.initialize({
// ... other config
onError: (error: BaseSdkException) => {
// Log to monitoring service
logErrorToMonitoring({
category: 'payment_error',
errorCode: error.code,
message: error.message,
exception: error.name,
userAgent: navigator.userAgent,
timestamp: Date.now()
});
// Track analytics
analytics.track('payment_failed', {
errorCode: error.code,
errorMessage: error.message,
retryCount: retryCount
});
// Check if error is retryable (network issues, timeouts)
const isNetworkError = error.code === 'SDK0500';
const isTimeout = error.message.toLowerCase().includes('timeout');
const isRetryable = isNetworkError || isTimeout ||
error.message.toLowerCase().includes('unavailable');
// Implement retry logic
if (isRetryable && retryCount < MAX_RETRIES) {
retryCount++;
showWarningMessage(
`Connection issue (attempt ${retryCount}/${MAX_RETRIES}). ` +
'Please try your payment again.',
{
action: 'Retry Payment',
onAction: () => {
// Retry the payment
document.getElementById('submit-btn').click();
}
}
);
return;
}
// Reset retry count for non-retryable errors
retryCount = 0;
// Show user-friendly error messages based on error code and message
let userMessage = 'Payment failed. Please try again or contact support.';
// Check by SDK error code
if (error.code === 'SDK0500') {
userMessage = 'Network connection issue. Please check your internet connection and try again.';
} else if (error.code === 'SDK1114') {
userMessage = '3D Secure authentication failed. Please try again or use a different card.';
} else if (error.code === 'SDK1115') {
userMessage = 'Payment authorisation failed. Please check your details and try again.';
} else if (error.code === 'SDK1116') {
// Card payment failed - check message for specifics
if (error.message.toLowerCase().includes('declined')) {
userMessage = 'Your card was declined. Please try a different card or contact your bank.';
} else if (error.message.toLowerCase().includes('insufficient funds')) {
userMessage = 'Insufficient funds. Please use a different payment method.';
} else if (error.message.toLowerCase().includes('expired')) {
userMessage = 'This card has expired. Please use a different card.';
} else if (error.message.toLowerCase().includes('cvv') ||
error.message.toLowerCase().includes('security code')) {
userMessage = 'Invalid security code. Please check the CVV on your card and try again.';
} else if (error.message.toLowerCase().includes('card number')) {
userMessage = 'Invalid card number. Please check and try again.';
} else if (error.message.toLowerCase().includes('expiry') ||
error.message.toLowerCase().includes('expiration')) {
userMessage = 'Invalid expiry date. Please check and try again.';
} else {
userMessage = 'Card payment failed. Please check your details and try again.';
}
} else if (error.code === 'SDK1117') {
userMessage = 'PayPal payment failed. Please try again or use a different payment method.';
} else if (error.code === 'SDK1118') {
userMessage = 'Google Pay payment failed. Please try again or use a different payment method.';
} else if (error.code === 'SDK1119') {
userMessage = 'Apple Pay payment failed. Please try again or use a different payment method.';
}
// Check by message content for scenarios without specific codes
else if (error.message.toLowerCase().includes('timeout')) {
userMessage = 'Request timed out. Please check your internet connection and try again.';
} else if (error.message.toLowerCase().includes('session') ||
error.message.toLowerCase().includes('expired')) {
userMessage = 'Your payment session has expired. Please refresh the page.';
} else if (error.message.toLowerCase().includes('unavailable')) {
userMessage = 'Payment service temporarily unavailable. Please try again in a few minutes.';
} else if (error.code && (error.code.startsWith('SDK01') ||
error.code.startsWith('SDK02'))) {
userMessage = 'Payment configuration error. Please contact support.';
} else if (error.message) {
userMessage = error.message;
}
showErrorMessage(userMessage);
// Offer alternative payment methods for certain errors
const shouldOfferAlternatives =
error.code === 'SDK1116' || // Card payment failed
error.code === 'SDK1117' || // PayPal failed
error.code === 'SDK1118' || // Google Pay failed
error.code === 'SDK1119' || // Apple Pay failed
error.message.toLowerCase().includes('declined') ||
error.message.toLowerCase().includes('insufficient funds');
if (shouldOfferAlternatives) {
showAlternativePaymentMethods();
}
// Show retry button for network/timeout errors
const shouldShowRetry =
error.code === 'SDK0500' ||
error.message.toLowerCase().includes('timeout') ||
error.message.toLowerCase().includes('unavailable');
if (shouldShowRetry) {
showRetryButton();
}
// Show refresh button for session errors
if (error.message.toLowerCase().includes('session') ||
error.message.toLowerCase().includes('expired')) {
showRefreshButton();
}
// Re-enable payment form
enablePaymentForm();
}
});Integrate with monitoring services like Sentry, Datadog, or custom logging.
import * as Sentry from '@sentry/browser';
const checkoutDropIn = CheckoutDropIn.initialize({
// ... other config
onError: (error: BaseSdkException) => {
// Log to Sentry
Sentry.captureException(error, {
tags: {
category: 'payment_error',
errorCode: error.code,
exceptionType: error.name
},
contexts: {
payment: {
errorCode: error.code,
message: error.message
}
}
});
// Log to custom monitoring service
fetch('/api/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'payment_error',
errorCode: error.code,
message: error.message,
exception: error.name,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: new Date().toISOString()
})
}).catch(err => {
// Silently fail - don't disrupt user experience
console.error('Failed to log error:', err);
});
// Show error to user
showErrorMessage(error.message);
}
});Here's a production-ready error handling implementation:
import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';
import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';
import * as Sentry from '@sentry/browser';
let retryCount = 0;
const MAX_RETRIES = 3;
const checkoutDropIn = CheckoutDropIn.initialize({
// ... other config
onError: (error: BaseSdkException) => {
// 1. Log error for debugging
console.error('Payment error:', {
errorCode: error.code,
message: error.message,
name: error.name
});
// 2. Send to monitoring service
Sentry.captureException(error, {
tags: {
category: 'payment_error',
errorCode: error.code
},
contexts: {
payment: {
errorCode: error.code,
message: error.message,
retryCount: retryCount
}
}
});
// 3. Track analytics
analytics.track('payment_failed', {
errorCode: error.code,
errorMessage: error.message,
retryCount: retryCount,
timestamp: Date.now()
});
// 4. Clear any loading state
clearTimeout(window.loadingTimeout);
hideLoadingOverlay();
// 5. Implement retry logic for transient errors
const isNetworkError = error.code === 'SDK0500';
const isTimeout = error.message.toLowerCase().includes('timeout');
const isUnavailable = error.message.toLowerCase().includes('unavailable');
if ((isNetworkError || isTimeout || isUnavailable) && retryCount < MAX_RETRIES) {
retryCount++;
showNotification({
type: 'warning',
message: `Connection issue (attempt ${retryCount}/${MAX_RETRIES}). Please try again.`,
actions: [
{
label: 'Retry payment',
onClick: () => retryPayment()
}
]
});
return;
}
// Reset retry count
retryCount = 0;
// 6. Show user-friendly error messages
let userMessage = 'Payment failed. Please try again or contact support.';
// Check by SDK error code
if (error.code === 'SDK0500') {
userMessage = 'Network error. Please check your connection and try again.';
} else if (error.code === 'SDK1114') {
userMessage = '3D Secure authentication failed. Please try again.';
} else if (error.code === 'SDK1115') {
userMessage = 'Payment authorisation failed. Please check your details and try again.';
} else if (error.code === 'SDK1116') {
// Card payment failed - check message
if (error.message.toLowerCase().includes('declined')) {
userMessage = 'Your card was declined. Please try a different card or contact your bank.';
} else if (error.message.toLowerCase().includes('insufficient funds')) {
userMessage = 'Insufficient funds. Please use a different payment method.';
} else if (error.message.toLowerCase().includes('expired')) {
userMessage = 'This card has expired. Please use a different card.';
} else if (error.message.toLowerCase().includes('cvv')) {
userMessage = 'Invalid security code. Please check and try again.';
} else {
userMessage = 'Card payment failed. Please check your details and try again.';
}
} else if (error.code === 'SDK1117') {
userMessage = 'PayPal payment failed. Please try again or use a different method.';
} else if (error.code === 'SDK1118') {
userMessage = 'Google Pay payment failed. Please try again or use a different method.';
} else if (error.code === 'SDK1119') {
userMessage = 'Apple Pay payment failed. Please try again or use a different method.';
} else if (error.message.toLowerCase().includes('session') ||
error.message.toLowerCase().includes('expired')) {
userMessage = 'Session expired. Please refresh the page.';
} else if (error.code && (error.code.startsWith('SDK01') ||
error.code.startsWith('SDK02'))) {
userMessage = 'Configuration error. Please contact support.';
} else if (error.message) {
userMessage = error.message;
}
// 7. Show error to user
showNotification({
type: 'error',
title: 'Payment failed',
message: userMessage,
duration: 8000
});
// 8. Offer recovery options
const shouldOfferAlternatives =
error.code === 'SDK1116' ||
error.code === 'SDK1117' ||
error.code === 'SDK1118' ||
error.code === 'SDK1119' ||
error.message.toLowerCase().includes('declined') ||
error.message.toLowerCase().includes('insufficient funds');
if (shouldOfferAlternatives) {
showAlternativePaymentMethods();
}
const shouldShowRetry =
error.code === 'SDK0500' ||
error.message.toLowerCase().includes('timeout');
if (shouldShowRetry) {
showRetryButton();
}
if (error.message.toLowerCase().includes('session') ||
error.message.toLowerCase().includes('expired')) {
showRefreshButton();
}
// 9. Re-enable UI
enablePaymentForm();
enableSubmitButton();
}
});
// Helper functions
function hideLoadingOverlay() {
document.getElementById('loading-overlay').style.display = 'none';
}
function enablePaymentForm() {
const formElements = document.querySelectorAll('#payment-form input, #payment-form button');
formElements.forEach(element => {
element.disabled = false;
});
}
function enableSubmitButton() {
const submitBtn = document.getElementById('submit-btn');
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Try Again';
}
}
function showAlternativePaymentMethods() {
// Show UI to let user choose different payment method
document.getElementById('alternative-methods').style.display = 'block';
}
function showRetryButton() {
// Show retry button
const retryBtn = document.createElement('button');
retryBtn.textContent = 'Retry Payment';
retryBtn.onclick = retryPayment;
document.getElementById('error-actions').appendChild(retryBtn);
}
function retryPayment() {
// Re-submit the payment
document.getElementById('submit-btn').click();
}For specific error codes and exceptions related to individual payment methods, see the payment method documentation: Card, PayPal, Apple Pay, Google Pay.