Error Handling
Learn how to handle errors from the Pixlpay API effectively.
Error Response Format
All errors follow a consistent structure:
json
{
"success": false,
"error": "ERROR_CODE",
"message": "Human-readable error message"
}For validation errors:
json
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "The given data was invalid",
"errors": {
"url": ["The url field is required."],
"events": ["The events field must be an array."]
}
}HTTP Status Codes
| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Request completed successfully |
| 201 | Created | Resource created successfully |
| 400 | Bad Request | Fix the request and retry |
| 401 | Unauthorized | Check authentication token |
| 403 | Forbidden | Token lacks required scope |
| 404 | Not Found | Resource doesn't exist |
| 422 | Validation Error | Fix validation errors and retry |
| 429 | Rate Limited | Wait and retry with backoff |
| 500 | Server Error | Retry later or contact support |
Common Errors
Authentication Errors (401)
json
{
"success": false,
"error": "Unauthorized",
"message": "Invalid or missing API token"
}Solutions:
- Check the
Authorizationheader format:Bearer YOUR_TOKEN - Verify the token hasn't been revoked
- Check the token hasn't expired
Permission Errors (403)
json
{
"success": false,
"error": "Forbidden",
"message": "Token does not have the required scope: orders:write"
}Solutions:
- Add the required scope to your token
- Create a new token with appropriate scopes
Not Found Errors (404)
json
{
"success": false,
"error": "Not Found",
"message": "Order not found"
}Solutions:
- Verify the resource ID is correct
- Ensure the resource belongs to your store
- Check if the resource was deleted
Validation Errors (422)
json
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "The given data was invalid",
"errors": {
"url": ["The url must be a valid URL."],
"events": ["The selected events.0 is invalid."]
}
}Solutions:
- Check the
errorsobject for specific field issues - Refer to API documentation for valid values
- Ensure required fields are provided
Rate Limit Errors (429)
json
{
"success": false,
"error": "Too Many Requests",
"message": "Rate limit exceeded. Retry after 60 seconds."
}Headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700745660Solutions:
- Implement exponential backoff
- Cache responses where appropriate
- Increase token rate limit if needed
Business Logic Errors (400)
json
{
"success": false,
"error": "ORDER_ALREADY_COMPLETED",
"message": "Order is already completed"
}Common codes:
ORDER_ALREADY_COMPLETED- Order already fulfilledINVALID_STATE- Resource in invalid state for operationLIMIT_EXCEEDED- Plan limit reached
Error Handling Best Practices
1. Always Check Success Flag
javascript
async function getProducts() {
const response = await fetch(`${BASE_URL}/products`, {
headers: { Authorization: `Bearer ${token}` }
});
const data = await response.json();
if (!data.success) {
throw new APIError(data.error, data.message, response.status);
}
return data.data;
}2. Implement Retry Logic
javascript
async function fetchWithRetry(url, options, maxRetries = 3) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
// Don't retry client errors (4xx except 429)
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
const data = await response.json();
throw new APIError(data.error, data.message, response.status);
}
// Handle rate limiting
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
continue;
}
// Retry server errors
if (response.status >= 500) {
throw new Error(`Server error: ${response.status}`);
}
return await response.json();
} catch (error) {
lastError = error;
if (error instanceof APIError) {
throw error; // Don't retry client errors
}
// Exponential backoff
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await sleep(delay);
}
}
throw lastError;
}3. Handle Validation Errors
javascript
function handleValidationErrors(errors) {
const messages = [];
for (const [field, fieldErrors] of Object.entries(errors)) {
for (const error of fieldErrors) {
messages.push(`${field}: ${error}`);
}
}
return messages;
}
try {
await createWebhook({ url: 'invalid-url' });
} catch (error) {
if (error.code === 'VALIDATION_ERROR') {
const messages = handleValidationErrors(error.errors);
console.error('Validation failed:', messages.join(', '));
}
}4. Log Errors Appropriately
javascript
function logAPIError(error, context) {
console.error('API Error', {
code: error.code,
message: error.message,
status: error.status,
endpoint: context.endpoint,
method: context.method,
timestamp: new Date().toISOString(),
});
// Send to monitoring service
monitoring.captureException(error, {
tags: { api: 'pixlpay' },
extra: context,
});
}5. Create an Error Class
javascript
class PixlpayError extends Error {
constructor(code, message, status, errors = null) {
super(message);
this.name = 'PixlpayError';
this.code = code;
this.status = status;
this.errors = errors;
}
isValidationError() {
return this.code === 'VALIDATION_ERROR';
}
isRateLimited() {
return this.status === 429;
}
isAuthError() {
return this.status === 401 || this.status === 403;
}
isRetryable() {
return this.status >= 500 || this.status === 429;
}
}Complete Example
javascript
class PixlpayClient {
constructor(token, baseUrl) {
this.token = token;
this.baseUrl = baseUrl;
}
async request(method, endpoint, data = null) {
const url = `${this.baseUrl}${endpoint}`;
const options = {
method,
headers: {
'Authorization': `Bearer ${this.token}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
};
if (data) {
options.body = JSON.stringify(data);
}
let lastError;
for (let attempt = 1; attempt <= 3; attempt++) {
try {
const response = await fetch(url, options);
const responseData = await response.json();
if (!responseData.success) {
throw new PixlpayError(
responseData.error,
responseData.message,
response.status,
responseData.errors
);
}
return responseData;
} catch (error) {
lastError = error;
if (error instanceof PixlpayError) {
if (!error.isRetryable()) {
throw error;
}
}
// Exponential backoff
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}
throw lastError;
}
async getProducts() {
return this.request('GET', '/products');
}
async fulfillOrder(orderId) {
return this.request('POST', `/orders/${orderId}/fulfill`);
}
}
// Usage
const client = new PixlpayClient(token, 'https://yourstore.pixlpay.net/api/external/v1');
try {
const products = await client.getProducts();
console.log('Products:', products.data);
} catch (error) {
if (error.isAuthError()) {
console.error('Authentication failed - check your token');
} else if (error.isValidationError()) {
console.error('Validation failed:', error.errors);
} else {
console.error('API error:', error.message);
}
}