Examples
Error Handling Example
Widget SDK Reference
Examples
Paysight API
Email Services
Payment API
- Card
Customer Service API
- API Reference
Admin API
- MerchantAccounts
Mitigation API
- API for Chargeback Mitigation Providers
Examples
Error Handling Example
Learn how to implement robust error handling with the PaySight Widget
Error Handling Example
This example demonstrates comprehensive error handling strategies for the PaySight Widget, including handling various error types, providing user feedback, and implementing recovery mechanisms.
Complete Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PaySight Widget - Error Handling</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.5;
margin: 0;
padding: 20px;
background-color: #f8fafc;
}
.container {
max-width: 600px;
margin: 40px auto;
background-color: white;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: 24px;
}
.header {
text-align: center;
margin-bottom: 24px;
}
.header h1 {
margin: 0;
color: #0f172a;
font-size: 24px;
}
.header p {
margin: 8px 0 0;
color: #64748b;
}
.widget-container {
border: 1px solid #e5e7eb;
border-radius: 6px;
padding: 20px;
margin-bottom: 20px;
}
.error-container {
margin-bottom: 20px;
}
.error-message {
background-color: #fee2e2;
border: 1px solid #ef4444;
color: #b91c1c;
padding: 12px 16px;
border-radius: 6px;
margin-bottom: 12px;
font-size: 14px;
display: none;
}
.error-details {
background-color: #fff1f2;
border: 1px solid #fecdd3;
color: #881337;
padding: 12px 16px;
border-radius: 6px;
font-size: 13px;
font-family: monospace;
white-space: pre-wrap;
display: none;
margin-top: 8px;
}
.error-actions {
display: none;
margin-top: 12px;
}
.error-action-button {
background-color: #ef4444;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
}
.error-action-button:hover {
background-color: #dc2626;
}
.error-action-button + .error-action-button {
margin-left: 8px;
background-color: #6b7280;
}
.error-action-button + .error-action-button:hover {
background-color: #4b5563;
}
.debug-panel {
margin-top: 24px;
padding: 16px;
background-color: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 6px;
}
.debug-panel h3 {
margin: 0 0 12px;
color: #0f172a;
font-size: 16px;
}
.debug-log {
background-color: white;
border: 1px solid #e2e8f0;
border-radius: 4px;
padding: 12px;
max-height: 200px;
overflow-y: auto;
font-family: monospace;
font-size: 13px;
line-height: 1.4;
}
.debug-entry {
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid #f1f5f9;
}
.debug-entry:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.debug-timestamp {
color: #64748b;
font-size: 12px;
}
.debug-type {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
margin: 0 8px;
}
.debug-type.error {
background-color: #fee2e2;
color: #b91c1c;
}
.debug-type.warning {
background-color: #fef3c7;
color: #92400e;
}
.debug-type.info {
background-color: #e0f2fe;
color: #0369a1;
}
.debug-message {
color: #0f172a;
}
.retry-button {
display: none;
margin-top: 16px;
background-color: #3b82f6;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
}
.retry-button:hover {
background-color: #2563eb;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Secure Payment</h1>
<p>Complete your payment with error handling demonstration</p>
</div>
<div class="error-container">
<div id="error-message" class="error-message"></div>
<div id="error-details" class="error-details"></div>
<div id="error-actions" class="error-actions">
<button class="error-action-button" onclick="retryPayment()">
Retry Payment
</button>
<button class="error-action-button" onclick="resetWidget()">
Reset Form
</button>
</div>
</div>
<div id="widget-container" class="widget-container"></div>
<button id="retry-button" class="retry-button" onclick="retryPayment()">
Try Again
</button>
<div class="debug-panel">
<h3>Debug Log</h3>
<div id="debug-log" class="debug-log"></div>
</div>
</div>
<!-- Add the PaySight Widget SDK -->
<script src="https://payment.paysight.io/widget-sdk.js"></script>
<script>
// Error types and messages
const ErrorTypes = {
VALIDATION: 'VALIDATION_ERROR',
NETWORK: 'NETWORK_ERROR',
PAYMENT: 'PAYMENT_ERROR',
WIDGET: 'ERROR',
SYSTEM: 'SYSTEM_ERROR'
};
const ErrorMessages = {
[ErrorTypes.VALIDATION]: {
title: 'Invalid Input',
message: 'Please check your input and try again.',
recoverable: true
},
[ErrorTypes.NETWORK]: {
title: 'Connection Error',
message: 'Unable to connect to the payment service.',
recoverable: true
},
[ErrorTypes.PAYMENT]: {
title: 'Payment Failed',
message: 'Unable to process your payment.',
recoverable: true
},
[ErrorTypes.WIDGET]: {
title: 'Widget Error',
message: 'The payment widget encountered an error.',
recoverable: false
},
[ErrorTypes.SYSTEM]: {
title: 'System Error',
message: 'An unexpected error occurred.',
recoverable: false
}
};
// Widget configuration
const config = {
productId: YOUR_PRODUCT_ID,
sessionId: \`session_\${Date.now()}\`,
amount: 2999,
environment: 'production',
threeDSRequired: true,
ecom: true,
currency: 'USD',
locale: 'en-US'
};
// Widget instance
let widget;
let retryCount = 0;
const MAX_RETRIES = 3;
const RETRY_DELAY = 2000;
// Initialize widget
function initializeWidget() {
try {
widget = PaySightSDK.createWidget({
targetId: 'widget-container',
config,
onReady: handleWidgetReady,
onError: handleError,
onMessage: handleWidgetMessage
});
logDebug('Widget initialized', 'info');
} catch (error) {
handleError({
type: ErrorTypes.SYSTEM,
message: 'Failed to initialize widget',
details: error
});
}
}
// Widget ready handler
function handleWidgetReady() {
logDebug('Widget ready', 'info');
hideError();
hideRetryButton();
}
// Error handler
function handleError(error) {
logDebug(\`Error: \${error.message}\`, 'error');
const errorType = getErrorType(error);
const errorInfo = ErrorMessages[errorType];
showError(
errorInfo.title,
error.message || errorInfo.message,
error.details,
errorInfo.recoverable
);
if (errorInfo.recoverable && retryCount < MAX_RETRIES) {
showRetryButton();
}
}
// Message handler for widget events
function handleWidgetMessage(message) {
switch (message.type) {
case 'VALIDATION_ERROR':
handleValidationError(message.payload);
break;
case 'PAYMENT_ERROR':
handlePaymentError(message.payload);
break;
case 'NETWORK_ERROR':
handleNetworkError(message.payload);
break;
case 'PAYMENT_3DS_ERROR':
handle3DSError(message.payload);
break;
case 'PAYMENT_SUCCESS':
handlePaymentSuccess(message.payload);
break;
}
}
// Error type handlers
function handlePaymentError(payload) {
handleError({
type: ErrorTypes.PAYMENT,
message: payload.message,
details: payload
});
}
function handleValidationError(payload) {
handleError({
type: ErrorTypes.VALIDATION,
message: 'Please check your card details',
details: payload
});
}
function handleNetworkError(payload) {
handleError({
type: ErrorTypes.NETWORK,
message: 'Connection failed. Please check your internet connection.',
details: payload
});
}
function handle3DSError(payload) {
handleError({
type: ErrorTypes.SYSTEM,
message: '3D Secure Error',
details: payload
});
}
function handlePaymentSuccess(payload) {
handleError({
type: ErrorTypes.SYSTEM,
message: 'Payment Successful',
details: payload
});
}
// Helper functions
function getErrorType(error) {
if (error.type) return error.type;
if (error.code?.includes('VALIDATION')) return ErrorTypes.VALIDATION;
if (error.code?.includes('NETWORK')) return ErrorTypes.NETWORK;
if (error.code?.includes('PAYMENT')) return ErrorTypes.PAYMENT;
if (error.code?.includes('WIDGET')) return ErrorTypes.WIDGET;
return ErrorTypes.SYSTEM;
}
function showError(title, message, details, recoverable) {
const errorMessage = document.getElementById('error-message');
const errorDetails = document.getElementById('error-details');
const errorActions = document.getElementById('error-actions');
errorMessage.textContent = \`\${title}: \${message}\`;
errorMessage.style.display = 'block';
if (details) {
errorDetails.textContent = JSON.stringify(details, null, 2);
errorDetails.style.display = 'block';
}
if (recoverable) {
errorActions.style.display = 'block';
}
}
function hideError() {
document.getElementById('error-message').style.display = 'none';
document.getElementById('error-details').style.display = 'none';
document.getElementById('error-actions').style.display = 'none';
}
function showRetryButton() {
document.getElementById('retry-button').style.display = 'block';
}
function hideRetryButton() {
document.getElementById('retry-button').style.display = 'none';
}
// Retry mechanism
function retryPayment() {
if (retryCount >= MAX_RETRIES) {
handleError({
type: ErrorTypes.SYSTEM,
message: 'Maximum retry attempts reached',
recoverable: false
});
return;
}
retryCount++;
logDebug(\`Retrying payment (attempt \${retryCount})\`, 'info');
setTimeout(() => {
resetWidget();
initializeWidget();
}, RETRY_DELAY);
}
function resetWidget() {
if (widget) {
widget.destroy();
}
hideError();
hideRetryButton();
initializeWidget();
retryCount = 0;
}
// Debug logging
function logDebug(message, type = 'info') {
const debugLog = document.getElementById('debug-log');
const entry = document.createElement('div');
entry.className = 'debug-entry';
const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
entry.innerHTML = \`
<span class="debug-timestamp">\${timestamp}</span>
<span class="debug-type \${type}">\${type.toUpperCase()}</span>
<span class="debug-message">\${message}</span>
\`;
debugLog.insertBefore(entry, debugLog.firstChild);
}
// Initialize on load
window.addEventListener('load', () => {
initializeWidget();
});
</script>
</body>
</html>
Key Components
1. Error Types and Messages
const ErrorTypes = {
VALIDATION: 'VALIDATION_ERROR',
NETWORK: 'NETWORK_ERROR',
PAYMENT: 'PAYMENT_ERROR',
WIDGET: 'ERROR',
SYSTEM: 'SYSTEM_ERROR'
};
const ErrorMessages = {
[ErrorTypes.VALIDATION]: {
title: 'Invalid Input',
message: 'Please check your input and try again.',
recoverable: true
},
// ... other error types
};
2. Error Handler
function handleError(error) {
const errorType = getErrorType(error);
const errorInfo = ErrorMessages[errorType];
showError(
errorInfo.title,
error.message || errorInfo.message,
error.details,
errorInfo.recoverable
);
if (errorInfo.recoverable && retryCount < MAX_RETRIES) {
showRetryButton();
}
}
3. Retry Mechanism
function retryPayment() {
if (retryCount >= MAX_RETRIES) {
handleError({
type: ErrorTypes.SYSTEM,
message: 'Maximum retry attempts reached',
recoverable: false
});
return;
}
retryCount++;
setTimeout(() => {
resetWidget();
initializeWidget();
}, RETRY_DELAY);
}
Implementation Steps
-
Define Error Types
- Categorize different error scenarios
- Define error messages and recovery options
- Set up error constants
-
Implement Error Handlers
- Create main error handler
- Add specific error type handlers
- Set up error recovery logic
-
Add Retry Mechanism
- Implement retry counter
- Add delay between retries
- Handle maximum retry limit
-
Create Debug Interface
- Add debug logging
- Create debug UI panel
- Log all events and errors
-
Add User Feedback
- Show error messages
- Display error details
- Provide retry options
Best Practices
- Categorize Errors
function getErrorType(error) {
// Network errors
if (error instanceof TypeError || error.name === 'NetworkError') {
return ErrorTypes.NETWORK;
}
// Validation errors
if (error.code?.startsWith('VALIDATION_')) {
return ErrorTypes.VALIDATION;
}
// Payment errors
if (error.code?.startsWith('PAYMENT_')) {
return ErrorTypes.PAYMENT;
}
return ErrorTypes.SYSTEM;
}
- Implement Circuit Breaker
class CircuitBreaker {
constructor() {
this.failures = 0;
this.lastFailure = null;
this.state = 'CLOSED';
}
recordFailure() {
this.failures++;
this.lastFailure = Date.now();
if (this.failures >= MAX_FAILURES) {
this.state = 'OPEN';
}
}
canRetry() {
if (this.state === 'OPEN') {
const timeSinceLastFailure = Date.now() - this.lastFailure;
if (timeSinceLastFailure > RESET_TIMEOUT) {
this.reset();
return true;
}
return false;
}
return true;
}
reset() {
this.failures = 0;
this.lastFailure = null;
this.state = 'CLOSED';
}
}
- Implement Error Recovery
async function attemptRecovery(error) {
const recoveryStrategies = {
[ErrorTypes.NETWORK]: async () => {
await checkConnectivity();
return retryPayment();
},
[ErrorTypes.VALIDATION]: () => {
resetForm();
return Promise.resolve();
},
[ErrorTypes.PAYMENT]: async () => {
await validatePaymentState();
return retryPayment();
}
};
const strategy = recoveryStrategies[error.type];
if (strategy) {
return strategy();
}
throw new Error('No recovery strategy available');
}
Next Steps
- Basic Integration Example - Simple implementation example
- Custom Styling Example - Customize widget appearance
- 3DS Integration Example - 3D Secure implementation
- Configuration Guide - Complete configuration options