Skip to content

Error handling

Understand error types, handle payment failures, and implement proper error recovery.

Overview

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.

Error callback

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);
  }
});

Error object structure

PropertyDescription
message
string
Human-readable error message describing what went wrong.
ErrorCode
string
SDK error code in format SDK#### (e.g., 'SDK1114' for authentication failed, 'SDK0500' for network error). Use this for programmatic error handling.
name
string
Exception class name (e.g., 'CheckoutDropInCardPaymentFailedSdkException').

Error categories

Errors are organised into four main categories based on their source and nature.

Configuration errors

Errors that occur during SDK initialisation or component rendering due to invalid configuration.

ExceptionError codeDescriptionSolution
CheckoutDropInConfigNotFoundSdkExceptionSDK1100Drop-in configuration not found or invalid.Verify initialisation parameters.
CheckoutDropInFailedToRenderCardSdkExceptionSDK1101Failed to render card component.Check session configuration for card support.
CheckoutDropInFailedToRenderPaypalSdkExceptionSDK1102Failed to render PayPal button.Verify PayPal is enabled in session.
CheckoutDropInFailedToRenderGooglePaySdkExceptionSDK1103Failed to render Google Pay button.Check Google Pay configuration.
CheckoutDropInFailedToRenderApplePaySdkExceptionSDK1104Failed to render Apple Pay button.Verify Apple Pay domain registration.
CheckoutDropInInvalidPaypalEntryTypeSdkExceptionSDK1120PayPal 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.'
    );
  }
}

Payment errors

Errors that occur during payment processing for specific payment methods.

ExceptionError codeDescriptionUser action
CheckoutDropInCardPaymentFailedSdkExceptionSDK1116Card payment failed (see detection patterns below).See card-specific patterns below.
CheckoutDropInPaypalPaymentFailedSdkExceptionSDK1117PayPal transaction failed.Try again or use different method.
CheckoutDropInGooglePayPaymentFailedSdkExceptionSDK1118Google Pay transaction failed.Try again or use different method.
CheckoutDropInApplePayPaymentFailedSdkExceptionSDK1119Apple Pay transaction failed.Try again or use different method.

Card-specific error detection patterns

Since card errors come from providers with varying message formats, use message-based detection:

ScenarioDetection approachUser action
Card declinederror.message contains "declined"Try a different card or contact bank.
Insufficient fundserror.message contains "insufficient funds"Use a different payment method.
Expired carderror.message contains "expired"Use a different card.
Invalid CVVerror.message contains "CVV" or "security code"Check security code and retry.
Invalid card numbererror.message contains "card number" or "invalid number"Check card number and retry.
Invalid expiryerror.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();
  }
}

Authentication errors

Errors related to 3D Secure (3DS) authentication for card payments.

ExceptionError codeDescriptionUser action
CheckoutDropInAuthenticationFailedSdkExceptionSDK11143DS 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.message contains "timeout"
  • Cancelled: error.message contains "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()
      });
    }
  }
}

Authorisation errors

Errors that occur during payment authorisation.

ExceptionError codeDescriptionSolution
CheckoutDropInAuthorisationFailedSdkExceptionSDK1115Payment authorisation failed.Check transaction details and retry.

System errors

Errors related to network connectivity, session state, and system availability.

Error codeDetection approachUser action
SDK0500Network error codeCheck connection and retry.
Message-basederror.message contains "session" or "expired"Refresh page and retry.
Message-basederror.message contains "timeout"Check connection and retry.
Message-basederror.message contains "unavailable" or "service"Try again later.
SDK01XX or SDK02XXConfiguration 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
    });
  }
}

Error handling patterns

Basic error handling

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();
  }
});

Advanced error handling with recovery

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();
  }
});

Error logging to monitoring service

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);
  }
});

Complete error handling example

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.