Error Handling
VesuvioPay uses conventional HTTP status codes and structured error responses to indicate the success or failure of API requests. This guide explains how to handle errors effectively in your integration.
HTTP Status Codes​
VesuvioPay API uses the following HTTP status codes:
| Status Code | Description | When to Expect |
|---|---|---|
| 200 OK | Request succeeded | Successful GET, PUT, PATCH, DELETE requests |
| 201 Created | Resource created successfully | Successful POST requests that create new resources |
| 400 Bad Request | Invalid request parameters or validation failed | Missing required fields, invalid data format |
| 401 Unauthorized | Authentication failed | Invalid or missing API key, expired JWT token |
| 403 Forbidden | Access denied | Insufficient permissions, wrong store access |
| 404 Not Found | Resource doesn't exist | Customer, product, order, or other resource not found |
| 409 Conflict | Resource conflict | Duplicate email/phone, resource already exists |
| 429 Too Many Requests | Rate limit exceeded | Too many requests in a short time period |
| 500 Internal Server Error | Server error | Unexpected server-side issue |
| 503 Service Unavailable | Service temporarily unavailable | Maintenance, temporary outage |
Error Response Structure​
All error responses follow a consistent JSON structure:
Basic Error Response​
{
"success": false,
"message": "Human-readable error description",
"errorCode": "SPECIFIC_ERROR_CODE"
}
Validation Error Response​
When validation fails (HTTP 400), the response includes detailed field-level errors:
{
"success": false,
"message": "Validation failed",
"errorCode": "VALIDATION_FAILED",
"errors": [
{
"field": "email",
"message": "Email address is required"
},
{
"field": "phoneNumber",
"message": "Invalid phone number format"
}
]
}
Error Code Reference​
Customer Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
CUSTOMER_NOT_FOUND | 404 | Customer doesn't exist | Verify customer ID is correct |
CUSTOMER_ALREADY_DELETED | 409 | Customer was already deleted | Cannot perform operations on deleted customers |
CUSTOMER_PROFILE_UPDATE_FAILED | 500 | Failed to update customer profile | Retry request or contact support |
Address Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
ADDRESS_NOT_FOUND | 404 | Address doesn't exist | Verify address ID is correct |
ADDRESS_CREATION_FAILED | 500 | Failed to create address | Check address data and retry |
ADDRESS_UPDATE_FAILED | 500 | Failed to update address | Retry request or contact support |
ADDRESS_DELETION_FAILED | 500 | Failed to delete address | Retry request or contact support |
INVALID_ADDRESS_DATA | 400 | Invalid address information | Check required fields and format |
Authentication Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
INVALID_TOKEN | 401 | JWT token is invalid | Obtain a new JWT token |
TOKEN_EXPIRED | 401 | JWT token has expired | Refresh or obtain a new token |
ACCESS_DENIED | 403 | Insufficient permissions | Use appropriate API key type |
INVALID_CREDENTIALS | 401 | Login credentials are incorrect | Verify username/password |
USER_NOT_FOUND | 404 | User account doesn't exist | Check user identifier |
USER_ALREADY_EXISTS | 409 | User with this email/phone exists | Use different credentials or login |
REGISTRATION_INCOMPLETE | 400 | Registration process not finished | Complete all registration steps |
AUTHENTICATION_FAILED | 401 | Authentication process failed | Retry authentication flow |
SOCIAL_AUTH_FAILED | 401 | Social login failed | Retry or use alternative method |
COMPANY_SETUP_FAILED | 500 | Failed to set up company | Contact support |
API Key Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
API_KEY_NOT_FOUND | 404 | API key doesn't exist | Verify API key ID |
INVALID_API_KEY | 401 | API key is invalid or malformed | Check API key format and value |
API_KEY_INACTIVE | 401 | API key has been revoked | Generate a new API key |
API_KEY_EXPIRED | 401 | API key has expired | Generate a new API key |
API_KEY_CREATION_FAILED | 500 | Failed to create API key | Retry or contact support |
API_KEY_UPDATE_FAILED | 500 | Failed to update API key | Retry or contact support |
API_KEY_ROTATION_FAILED | 500 | Failed to rotate API key | Retry or contact support |
API_KEY_REVOCATION_FAILED | 500 | Failed to revoke API key | Retry or contact support |
NO_STORE_ACCESS | 403 | API key lacks store access | Use correct API key for this store |
Email & Phone Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
EMAIL_ALREADY_IN_USE | 409 | Email is registered to another account | Use different email or login |
EMAIL_VERIFICATION_FAILED | 400 | Email verification failed | Retry verification process |
EMAIL_CHANGE_NOT_AVAILABLE | 400 | Email change not allowed | Check account restrictions |
EMAIL_CHANGE_FAILED | 500 | Failed to change email | Retry or contact support |
PHONE_ALREADY_IN_USE | 409 | Phone number is registered | Use different number or login |
PHONE_VERIFICATION_FAILED | 400 | Phone verification failed | Retry verification process |
PHONE_CHANGE_NOT_AVAILABLE | 400 | Phone change not allowed | Check account restrictions |
INVALID_PHONE_FORMAT | 400 | Phone number format invalid | Use E.164 format (+1234567890) |
PHONE_CHANGE_FAILED | 500 | Failed to change phone | Retry or contact support |
Payment Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
PAYMENT_GATEWAY_ERROR | 500 | Payment gateway returned error | Check gateway status, retry |
PAYMENT_METHOD_NOT_FOUND | 404 | Payment method doesn't exist | Verify payment method ID |
PAYMENT_METHOD_CREATION_FAILED | 500 | Failed to create payment method | Check payment details, retry |
PAYMENT_PROCESSING_FAILED | 500 | Payment processing failed | Verify payment details, retry |
PAYMENT_INTENT_CREATION_FAILED | 500 | Failed to create payment intent | Retry or contact support |
PAYMENT_INTENT_CONFIRMATION_FAILED | 500 | Failed to confirm payment intent | Verify payment details, retry |
TRANSFER_CREATION_FAILED | 500 | Failed to create transfer | Retry or contact support |
WEBHOOK_VALIDATION_FAILED | 400 | Webhook signature invalid | Check webhook secret configuration |
Payment Account Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
PAYMENT_ACCOUNT_NOT_FOUND | 404 | Payment account doesn't exist | Verify account ID |
PAYMENT_ACCOUNT_CREATION_FAILED | 500 | Failed to create payment account | Retry or contact support |
PAYMENT_ACCOUNT_UPDATE_FAILED | 500 | Failed to update payment account | Retry or contact support |
EXTERNAL_ACCOUNT_ID_MISSING | 400 | External account ID required | Provide Stripe account ID |
Card & Bank Account Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
CARD_NOT_FOUND | 404 | Card doesn't exist | Verify card ID |
CARD_CREATION_FAILED | 500 | Failed to create card | Check card details, retry |
CARD_DELETION_FAILED | 500 | Failed to delete card | Retry or contact support |
CANNOT_DELETE_DEFAULT_CARD | 400 | Cannot delete default card | Set new default first |
CARD_SYNC_FAILED | 500 | Failed to sync card | Retry or contact support |
SET_DEFAULT_CARD_FAILED | 500 | Failed to set default card | Retry or contact support |
STRIPE_CUSTOMER_CREATION_FAILED | 500 | Failed to create Stripe customer | Retry or contact support |
BANK_ACCOUNT_NOT_FOUND | 404 | Bank account doesn't exist | Verify account ID |
BANK_ACCOUNT_CREATION_FAILED | 500 | Failed to create bank account | Check account details, retry |
BANK_ACCOUNT_DELETION_FAILED | 500 | Failed to delete bank account | Retry or contact support |
CANNOT_DELETE_DEFAULT_BANK_ACCOUNT | 400 | Cannot delete default account | Set new default first |
BANK_ACCOUNT_SYNC_FAILED | 500 | Failed to sync bank account | Retry or contact support |
Cart & Checkout Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
CART_NOT_FOUND | 404 | Cart doesn't exist | Create a new cart |
EMPTY_CART | 400 | Cart has no items | Add items before checkout |
CHECKOUT_NOT_FOUND | 404 | Checkout session doesn't exist | Verify checkout ID or create new |
CHECKOUT_CREATION_FAILED | 500 | Failed to create checkout | Retry or contact support |
CHECKOUT_INVALID_STATE | 400 | Checkout in invalid state | Verify checkout status |
INSUFFICIENT_PAYMENT_METHODS | 400 | No valid payment method | Add payment method |
Product & Inventory Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
PRODUCT_NOT_FOUND | 404 | Product doesn't exist | Verify product ID |
PRODUCT_VARIANT_NOT_FOUND | 404 | Product variant doesn't exist | Verify variant ID |
INSUFFICIENT_INVENTORY | 400 | Not enough stock available | Reduce quantity or wait for restock |
PRODUCT_OUT_OF_STOCK | 400 | Product is out of stock | Remove from cart or wait for restock |
INVENTORY_LIMIT_EXCEEDED | 400 | Requested quantity too high | Reduce quantity to available stock |
Order Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
ORDER_NOT_FOUND | 404 | Order doesn't exist | Verify order ID |
Subscription & Invoice Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
SUBSCRIPTION_NOT_FOUND | 404 | Subscription doesn't exist | Verify subscription ID |
PLAN_NOT_FOUND | 404 | Subscription plan doesn't exist | Verify plan ID |
INVOICE_NOT_FOUND | 404 | Invoice doesn't exist | Verify invoice ID |
INVOICE_NOT_PAID | 400 | Invoice has not been paid | Process payment first |
INVOICE_DOWNLOAD_FAILED | 500 | Failed to download invoice | Retry or contact support |
File Upload Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
FILE_NOT_PROVIDED | 400 | No file was uploaded | Include file in request |
FILE_SIZE_EXCEEDED | 400 | File size too large | Reduce file size |
INVALID_FILE_FORMAT | 400 | File format not supported | Use supported format |
INVALID_CONTENT_TYPE | 400 | Content-Type header incorrect | Set proper Content-Type |
FILE_UPLOAD_FAILED | 500 | File upload failed | Retry or contact support |
SMS & Template Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
SMS_NOT_FOUND | 404 | SMS record doesn't exist | Verify SMS ID |
TWILIO_SETTINGS_NOT_FOUND | 404 | Twilio configuration missing | Configure Twilio settings |
TEMPLATE_TYPE_NOT_FOUND | 404 | Template type doesn't exist | Verify template type |
TEMPLATE_WORD_NOT_FOUND | 404 | Template word doesn't exist | Verify template word |
TEMPLATE_NOT_FOUND | 404 | Template doesn't exist | Verify template ID |
TEMPLATE_CREATION_FAILED | 500 | Failed to create template | Retry or contact support |
TEMPLATE_UPDATE_FAILED | 500 | Failed to update template | Retry or contact support |
TEMPLATE_DELETION_FAILED | 500 | Failed to delete template | Retry or contact support |
TEMPLATE_IN_USE | 400 | Template is being used | Cannot delete active template |
Platform & Store Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
PLATFORM_NOT_FOUND | 404 | Platform doesn't exist | Verify platform ID |
STORE_NOT_FOUND | 404 | Store doesn't exist | Verify store ID |
COMPANY_NOT_FOUND | 404 | Company doesn't exist | Verify company ID |
General Errors​
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
VALIDATION_FAILED | 400 | Request validation failed | Check errors array for details |
INVALID_INPUT | 400 | Input data is invalid | Verify request parameters |
INVALID_OPERATION | 400 | Operation not allowed | Check resource state |
INVALID_ENTITY_TYPE | 400 | Entity type is invalid | Use valid entity type |
STORE_ID_REQUIRED | 400 | Store ID is required | Include store ID in request |
INVALID_PREFIX | 400 | ID prefix is invalid | Use valid prefix |
RESOURCE_NOT_FOUND | 404 | Requested resource not found | Verify resource identifier |
DUPLICATE_RESOURCE | 409 | Resource already exists | Use different identifier |
INTERNAL_ERROR | 500 | Internal server error | Retry or contact support |
INTERNAL_SERVER_ERROR | 500 | Internal server error | Retry or contact support |
SERVICE_UNAVAILABLE | 503 | Service temporarily unavailable | Wait and retry with backoff |
TIMEOUT | 504 | Request timeout | Retry request |
HTTP_REQUEST_FAILED | 500 | HTTP request failed | Check network, retry |
Common Error Scenarios​
Scenario 1: Invalid API Key​
Problem: Using an incorrect or revoked API key
{
"success": false,
"message": "Invalid API key",
"errorCode": "INVALID_API_KEY"
}
Solution:
- Verify your API key is correct
- Check if the key has been revoked
- Ensure you're using the right environment key (test vs live)
- Generate a new API key if necessary
Scenario 2: Resource Not Found​
Problem: Attempting to access a non-existent resource
{
"success": false,
"message": "Customer not found",
"errorCode": "CUSTOMER_NOT_FOUND"
}
Solution:
- Verify the resource ID is correct
- Check if the resource was deleted
- Ensure you're searching in the correct store
- Handle 404 errors gracefully in your application
Scenario 3: Validation Errors​
Problem: Submitting invalid data
{
"success": false,
"message": "Validation failed",
"errorCode": "VALIDATION_FAILED",
"errors": [
{
"field": "email",
"message": "Email address is required"
},
{
"field": "phoneNumber",
"message": "Phone number must be in E.164 format"
}
]
}
Solution:
- Check all required fields are provided
- Validate data format before sending
- Display field-level errors to users
- Refer to API documentation for field requirements
Scenario 4: Duplicate Resource​
Problem: Attempting to create a resource that already exists
{
"success": false,
"message": "Email already in use",
"errorCode": "EMAIL_ALREADY_IN_USE"
}
Solution:
- Check if the resource exists before creating
- Use update endpoint instead of create
- Implement proper conflict handling
- Inform users about existing resources
Scenario 5: Rate Limiting​
Problem: Exceeding API rate limits
{
"success": false,
"message": "Too many requests",
"errorCode": "RATE_LIMIT_EXCEEDED"
}
Solution:
- Implement exponential backoff
- Cache responses when possible
- Batch requests if supported
- Monitor rate limit headers
Scenario 6: Payment Processing Failed​
Problem: Payment processing encountered an error
{
"success": false,
"message": "Payment processing failed",
"errorCode": "PAYMENT_PROCESSING_FAILED"
}
Solution:
- Verify payment method details
- Check if payment method is valid
- Ensure sufficient funds
- Ask customer to try a different payment method
- Contact support if issue persists
Retry Logic Recommendations​
When to Retry​
Retry requests for these scenarios:
- Network errors: Connection timeouts, DNS failures
- HTTP 429: Rate limit exceeded
- HTTP 500: Internal server error
- HTTP 503: Service unavailable
- HTTP 504: Gateway timeout
When NOT to Retry​
Do not retry for these errors:
- HTTP 400: Bad request (fix the request instead)
- HTTP 401: Unauthorized (update credentials)
- HTTP 403: Forbidden (check permissions)
- HTTP 404: Not found (resource doesn't exist)
- HTTP 409: Conflict (handle conflict resolution)
Exponential Backoff Strategy​
Implement exponential backoff for retries:
async function makeRequestWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
// Success - return response
if (response.ok) {
return await response.json();
}
// Don't retry client errors (4xx except 429)
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
const error = await response.json();
throw new Error(`API Error: ${error.message}`);
}
// Retry on 429, 5xx errors
if (response.status === 429 || response.status >= 500) {
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
console.log(`Retry attempt ${attempt + 1} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
} catch (error) {
// Network error - retry
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Network error, retry after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
// C# Retry with Exponential Backoff
public async Task<T> MakeRequestWithRetryAsync<T>(
Func<Task<HttpResponseMessage>> requestFunc,
int maxRetries = 3)
{
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
{
var response = await requestFunc();
// Success
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(content);
}
// Don't retry client errors (except 429)
if ((int)response.StatusCode >= 400 &&
(int)response.StatusCode < 500 &&
response.StatusCode != HttpStatusCode.TooManyRequests)
{
var error = await response.Content.ReadAsStringAsync();
throw new ApiException($"API Error: {error}");
}
// Retry on 429, 5xx
if (response.StatusCode == HttpStatusCode.TooManyRequests ||
(int)response.StatusCode >= 500)
{
var delay = (int)Math.Pow(2, attempt) * 1000;
Console.WriteLine($"Retry attempt {attempt + 1} after {delay}ms");
await Task.Delay(delay);
continue;
}
}
catch (HttpRequestException ex)
{
// Network error - retry
if (attempt < maxRetries - 1)
{
var delay = (int)Math.Pow(2, attempt) * 1000;
Console.WriteLine($"Network error, retry after {delay}ms");
await Task.Delay(delay);
continue;
}
throw;
}
}
throw new Exception("Max retries exceeded");
}
Error Handling Best Practices​
1. Always Check Response Status​
Always verify the response status before processing data:
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
console.error('API Error:', error.errorCode, error.message);
// Handle error appropriately
throw new Error(error.message);
}
const data = await response.json();
// Process successful response
2. Use try-catch Blocks​
Wrap API calls in try-catch blocks:
try {
const customer = await getCustomer(customerId);
// Process customer data
} catch (error) {
if (error.errorCode === 'CUSTOMER_NOT_FOUND') {
// Handle missing customer
console.log('Customer does not exist');
} else if (error.errorCode === 'INVALID_API_KEY') {
// Handle authentication error
console.error('Authentication failed');
} else {
// Handle unexpected errors
console.error('Unexpected error:', error);
}
}
// C# Example
try
{
var customer = await GetCustomerAsync(customerId);
// Process customer data
}
catch (ApiException ex) when (ex.ErrorCode == "CUSTOMER_NOT_FOUND")
{
// Handle missing customer
Console.WriteLine("Customer does not exist");
}
catch (ApiException ex) when (ex.ErrorCode == "INVALID_API_KEY")
{
// Handle authentication error
Console.Error.WriteLine("Authentication failed");
}
catch (Exception ex)
{
// Handle unexpected errors
Console.Error.WriteLine($"Unexpected error: {ex.Message}");
}
3. Log Errors for Debugging​
Log errors with context for troubleshooting:
function logError(error, context) {
console.error('VesuvioPay API Error', {
timestamp: new Date().toISOString(),
errorCode: error.errorCode,
message: error.message,
context: context,
statusCode: error.statusCode
});
// Send to error tracking service
// errorTracker.captureException(error, { context });
}
4. Display User-Friendly Messages​
Don't expose technical errors to end users:
function getUserFriendlyMessage(errorCode) {
const messages = {
'CUSTOMER_NOT_FOUND': 'We couldn\'t find your account. Please try again.',
'PAYMENT_PROCESSING_FAILED': 'Your payment could not be processed. Please check your payment details.',
'INSUFFICIENT_INVENTORY': 'This item is out of stock. Please try a different product.',
'INVALID_API_KEY': 'Authentication failed. Please contact support.',
'RATE_LIMIT_EXCEEDED': 'Too many requests. Please wait a moment and try again.'
};
return messages[errorCode] || 'An unexpected error occurred. Please try again later.';
}
5. Implement Proper Error Boundaries​
For frontend applications, use error boundaries:
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
logError(error, { component: errorInfo.componentStack });
}
render() {
if (this.state.hasError) {
return (
<div className="error-container">
<h2>Something went wrong</h2>
<p>Please refresh the page or contact support.</p>
</div>
);
}
return this.props.children;
}
}
6. Validate Before Sending​
Validate data client-side before making API requests:
function validateCustomerData(data) {
const errors = [];
if (!data.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
errors.push({ field: 'email', message: 'Valid email is required' });
}
if (!data.phoneNumber || !/^\+[1-9]\d{1,14}$/.test(data.phoneNumber)) {
errors.push({ field: 'phoneNumber', message: 'Phone must be in E.164 format' });
}
if (errors.length > 0) {
throw { errorCode: 'VALIDATION_FAILED', errors };
}
}
7. Monitor and Alert​
Set up monitoring for critical errors:
// Monitor error rates
function trackError(errorCode, statusCode) {
// Send to analytics/monitoring service
analytics.track('api_error', {
error_code: errorCode,
status_code: statusCode,
timestamp: Date.now()
});
// Alert on critical errors
if (statusCode >= 500 || errorCode === 'PAYMENT_PROCESSING_FAILED') {
alerting.send({
severity: 'high',
message: `Critical API error: ${errorCode}`,
statusCode: statusCode
});
}
}
8. Handle Validation Errors Gracefully​
Display field-level validation errors:
function displayValidationErrors(errors) {
// Clear previous errors
document.querySelectorAll('.error-message').forEach(el => el.remove());
// Display new errors
errors.forEach(error => {
const field = document.querySelector(`[name="${error.field}"]`);
if (field) {
const errorElement = document.createElement('span');
errorElement.className = 'error-message';
errorElement.textContent = error.message;
field.parentNode.appendChild(errorElement);
field.classList.add('error');
}
});
}
Testing Error Handling​
Test Different Error Scenarios​
describe('VesuvioPay Error Handling', () => {
test('handles CUSTOMER_NOT_FOUND error', async () => {
// Mock API to return 404
mockFetch.mockResolvedValueOnce({
ok: false,
status: 404,
json: async () => ({
success: false,
errorCode: 'CUSTOMER_NOT_FOUND',
message: 'Customer not found'
})
});
await expect(getCustomer('invalid-id'))
.rejects.toThrow('Customer not found');
});
test('retries on 500 error', async () => {
// First two calls fail, third succeeds
mockFetch
.mockResolvedValueOnce({ ok: false, status: 500 })
.mockResolvedValueOnce({ ok: false, status: 500 })
.mockResolvedValueOnce({
ok: true,
json: async () => ({ success: true, data: {} })
});
const result = await makeRequestWithRetry(url, options);
expect(mockFetch).toHaveBeenCalledTimes(3);
});
});
Always test both success and error paths in your integration to ensure graceful error handling.
Next Steps​
- Rate Limiting - Understand API rate limits and quotas
- Webhooks - Handle webhook events and errors
- Support - Contact support for help
If you encounter errors not covered in this guide, please contact support at support@vesuviopay.com with:
- Error code and message
- Request details (endpoint, parameters)
- Steps to reproduce
- Expected vs actual behavior