Examples
Error Handling Example
Complete example of handling errors when using One2Pays API.
Overview
This example shows how to:
- Handle different error types
- Implement retry logic for transient errors
- Provide user-friendly error messages
Error Handling Pattern
import crypto from 'crypto';
type ApiError = {
success: false;
error: {
code: string;
message: string;
metadata?: Record<string, unknown>;
};
};
type ApiSuccess<T> = {
success: true;
data: T;
};
type ApiResponse<T> = ApiSuccess<T> | ApiError;
// Error handling wrapper
async function handleApiCall<T>(
apiCall: () => Promise<Response>
): Promise<ApiResponse<T>> {
try {
const response = await apiCall();
const result = await response.json();
if (!result.success) {
return handleError(result.error);
}
return result as ApiSuccess<T>;
} catch (error) {
return {
success: false,
error: {
code: 'NETWORK_ERROR',
message: 'Network error occurred',
},
};
}
}
// Handle different error types
function handleError(error: any): ApiError {
switch (error.code) {
case 'VALIDATION_ERROR':
case 'INVALID_AMOUNT':
return {
success: false,
error: {
code: error.code,
message: 'Invalid amount format. Please check your amount.',
metadata: error.metadata,
},
};
case 'INSUFFICIENT_BALANCE':
return {
success: false,
error: {
code: error.code,
message: 'Insufficient wallet balance. Please top up your wallet.',
metadata: error.metadata,
},
};
case 'INVALID_CREDENTIALS':
return {
success: false,
error: {
code: error.code,
message: 'Authentication failed. Please check your API credentials.',
metadata: error.metadata,
},
};
case 'RATE_LIMIT_EXCEEDED':
return {
success: false,
error: {
code: error.code,
message: 'Too many requests. Please wait a moment and try again.',
metadata: error.metadata,
},
};
default:
return {
success: false,
error: {
code: error.code || 'UNKNOWN_ERROR',
message: error.message || 'An unexpected error occurred',
metadata: error.metadata,
},
};
}
}
// Retry logic with exponential backoff
async function retryApiCall<T>(
apiCall: () => Promise<ApiResponse<T>>,
maxRetries: number = 3
): Promise<ApiResponse<T>> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const result = await apiCall();
if (result.success) {
return result;
}
// Don't retry on client errors (4xx)
if (
result.error.code === 'VALIDATION_ERROR' ||
result.error.code === 'INVALID_CREDENTIALS' ||
result.error.code === 'FORBIDDEN' ||
result.error.code === 'RESOURCE_NOT_FOUND'
) {
return result;
}
// Retry on server errors (5xx) or rate limits
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
const retryAfter = (result.error.metadata as any)?.retryAfter || delay / 1000;
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}
}
return {
success: false,
error: {
code: 'RETRY_EXHAUSTED',
message: 'Request failed after multiple retries',
},
};
}
// Usage example
async function createPaymentWithErrorHandling(
amount: string,
referenceId: string,
customerBankAccount: {
name: string;
number: string;
code: string;
}
) {
const result = await retryApiCall(async () => {
return handleApiCall(async () => {
// Create payment API call
const method = 'POST';
const path = '/api/v1/payments';
const body = JSON.stringify({
amount,
currency: 'THB',
referenceId,
paymentMethod: 'promptpay',
customerBankAccountName: customerBankAccount.name,
customerBankAccountNumber: customerBankAccount.number,
customerBankCode: customerBankAccount.code,
});
const timestamp = Date.now().toString(); // milliseconds
// Signature format: HMAC-SHA256(timestamp + "." + rawBody, secretKey)
const message = `${timestamp}.${body}`;
const signature = crypto
.createHmac('sha256', API_SECRET)
.update(message)
.digest('hex');
return fetch(`https://api.example.com${path}`, {
method,
headers: {
'X-API-Key': API_KEY,
'X-Timestamp': timestamp,
'X-Signature': `sha256=${signature}`,
'Content-Type': 'application/json',
},
body,
});
});
});
if (!result.success) {
// Show user-friendly error message
console.error('Payment creation failed:', result.error.message);
return null;
}
return result.data;
}User-Friendly Error Messages
Always provide user-friendly error messages:
function getUserFriendlyMessage(error: ApiError): string {
const messages: Record<string, string> = {
VALIDATION_ERROR: 'Please check your input and try again',
INVALID_AMOUNT: 'Please enter a valid amount',
INSUFFICIENT_BALANCE: 'Your wallet balance is insufficient. Please top up.',
INVALID_CREDENTIALS: 'Authentication error. Please contact support.',
RATE_LIMIT_EXCEEDED: 'Too many requests. Please try again in a moment.',
RESOURCE_NOT_FOUND: 'Payment not found',
NETWORK_ERROR: 'Network error. Please check your connection.',
};
return messages[error.error.code] || 'An error occurred. Please try again.';
}