Error Response Format
All Xerobi APIs return errors in a consistent JSON format to make error handling predictable.Standard Error Structure
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {
// Additional error-specific information
}
}
}
Common Error Codes
Authentication Errors
| Error Code | HTTP Status | Description | Solution |
|---|---|---|---|
INVALID_API_KEY | 401 | API key is invalid or malformed | Check your API key in dashboard |
MISSING_AUTH_HEADER | 401 | Authorization header missing | Include Authorization: Bearer YOUR_KEY |
INSUFFICIENT_PERMISSIONS | 403 | API key lacks required permissions | Create key with proper permissions |
EXPIRED_API_KEY | 401 | API key has expired | Generate new key in dashboard |
INVALID_VERSION | 400 | API version not supported | Use Xerobi-Version: 2026-01-01 |
Request Errors
| Error Code | HTTP Status | Description | Solution |
|---|---|---|---|
INVALID_REQUEST | 400 | Request malformed or missing required fields | Check request format and required fields |
VALIDATION_ERROR | 400 | Field validation failed | Review field types and constraints |
RATE_LIMIT_EXCEEDED | 429 | Too many requests | Implement exponential backoff |
RESOURCE_NOT_FOUND | 404 | Requested resource doesn’t exist | Verify resource ID and endpoint |
METHOD_NOT_ALLOWED | 405 | HTTP method not supported | Use correct HTTP method |
Payment-Specific Errors
| Error Code | HTTP Status | Description | Solution |
|---|---|---|---|
CARD_DECLINED | 402 | Payment method was declined | Try different payment method |
INSUFFICIENT_FUNDS | 402 | Account has insufficient funds | Add funds or use different method |
PAYMENT_INTENT_EXPIRED | 400 | Payment intent has expired | Create new payment intent |
AMOUNT_TOO_LARGE | 400 | Amount exceeds maximum allowed | Reduce amount or contact support |
SMS-Specific Errors
| Error Code | HTTP Status | Description | Solution |
|---|---|---|---|
INSUFFICIENT_BALANCE | 402 | SMS balance too low | Top up account balance |
INVALID_RECIPIENT | 400 | Phone number format invalid | Check phone number format |
SENDER_ID_UNAVAILABLE | 400 | Sender ID not approved | Request sender ID approval |
MESSAGE_TOO_LONG | 400 | SMS exceeds character limit | Shorten message or use multiple parts |
Certification Errors
| Error Code | HTTP Status | Description | Solution |
|---|---|---|---|
CREDENTIAL_ALREADY_EXISTS | 409 | Credential ID already in use | Use unique credential identifier |
INVALID_CREDENTIAL_DATA | 400 | Credential data malformed | Validate credential format |
VERIFICATION_FAILED | 400 | Credential verification failed | Check credential authenticity |
Implementing Error Handling
Basic Error Handling
async function makeApiCall(endpoint, data) {
try {
const response = await fetch(`https://api.hixbe.com${endpoint}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.HIXBE_API_KEY}`,
'Xerobi-Version': '2026-01-01',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (!result.success) {
throw new HixbeError(result.error);
}
return result.data;
} catch (error) {
if (error instanceof HixbeError) {
handleHixbeError(error);
} else {
handleNetworkError(error);
}
}
}
class HixbeError extends Error {
constructor(error) {
super(error.message);
this.code = error.code;
this.details = error.details;
}
}
import requests
from requests.exceptions import RequestException
class HixbeClient:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.hixbe.com"
def _request(self, method, endpoint, data=None):
headers = {
'Authorization': f'Bearer {self.api_key}',
'Xerobi-Version': '2026-01-01',
'Content-Type': 'application/json'
}
try:
response = requests.request(
method,
f"{self.base_url}{endpoint}",
json=data,
headers=headers
)
result = response.json()
if not result.get('success', True):
raise HixbeError(result['error'])
return result.get('data')
except RequestException as e:
raise NetworkError(f"Network error: {e}")
except ValueError as e:
raise ParseError(f"Failed to parse response: {e}")
class HixbeError(Exception):
def __init__(self, error):
super().__init__(error['message'])
self.code = error['code']
self.details = error.get('details', {})
<?php
class HixbeClient {
private $apiKey;
private $baseUrl = 'https://api.hixbe.com';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function request($method, $endpoint, $data = null) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->baseUrl . $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->apiKey,
'Xerobi-Version: 2026-01-01',
'Content-Type: application/json'
]);
if ($method === 'POST' && $data) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_error($ch)) {
throw new NetworkException('Network error: ' . curl_error($ch));
}
curl_close($ch);
$result = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new ParseException('Failed to parse JSON response');
}
if (!$result['success']) {
throw new HixbeException($result['error']);
}
return $result['data'];
}
}
class HixbeException extends Exception {
public $errorCode;
public $errorDetails;
public function __construct($error) {
parent::__construct($error['message']);
$this->errorCode = $error['code'];
$this->errorDetails = $error['details'] ?? [];
}
}
?>
Error-Specific Handling
function handleHixbeError(error) {
switch (error.code) {
case 'RATE_LIMIT_EXCEEDED':
// Implement exponential backoff
return retryWithBackoff();
case 'INVALID_API_KEY':
// Log security issue and alert admin
console.error('Invalid API key used');
throw new SecurityException('API key compromised');
case 'CARD_DECLINED':
// Handle payment failure
notifyUser('Payment was declined. Please try a different card.');
break;
case 'INSUFFICIENT_BALANCE':
// Handle SMS balance issue
alertAdmin('SMS balance running low');
break;
default:
// Log unknown errors for investigation
console.error('Unknown error:', error);
throw error;
}
}
Retry Logic and Backoff
Exponential Backoff Implementation
class RetryHandler {
constructor(maxRetries = 3, baseDelay = 1000) {
this.maxRetries = maxRetries;
this.baseDelay = baseDelay;
}
async executeWithRetry(operation) {
let lastError;
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
if (!this.shouldRetry(error) || attempt === this.maxRetries) {
throw error;
}
const delay = this.calculateDelay(attempt);
await this.sleep(delay);
}
}
throw lastError;
}
shouldRetry(error) {
// Retry on network errors and server errors
const retryableCodes = ['RATE_LIMIT_EXCEEDED', 'INTERNAL_SERVER_ERROR'];
return error.code && retryableCodes.includes(error.code);
}
calculateDelay(attempt) {
// Exponential backoff with jitter
const exponentialDelay = this.baseDelay * Math.pow(2, attempt);
const jitter = Math.random() * 0.1 * exponentialDelay;
return exponentialDelay + jitter;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const retryHandler = new RetryHandler();
const result = await retryHandler.executeWithRetry(async () => {
return await makeApiCall('/payment/payment_intents', paymentData);
});
Idempotency for Critical Operations
Implementing Idempotency
async function createPaymentIntent(data, idempotencyKey) {
const response = await fetch('https://api.hixbe.com/payment/payment_intents', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.HIXBE_API_KEY}`,
'Xerobi-Version': '2026-01-01',
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey // Include idempotency key
},
body: JSON.stringify(data)
});
return response.json();
}
// Generate unique idempotency keys
function generateIdempotencyKey() {
return `payment_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// Safe retry with idempotency
async function createPaymentSafely(paymentData) {
const idempotencyKey = generateIdempotencyKey();
try {
return await createPaymentIntent(paymentData, idempotencyKey);
} catch (error) {
if (error.code === 'RATE_LIMIT_EXCEEDED') {
// Safe to retry with same key
await sleep(2000);
return await createPaymentIntent(paymentData, idempotencyKey);
}
throw error;
}
}
Rate Limiting
Understanding Rate Limits
Xerobi implements rate limiting to ensure fair usage:- Payment API: 100 requests per minute per API key
- SMS API: 50 requests per minute per API key
- Certification API: 200 requests per minute per API key
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995260
X-RateLimit-Retry-After: 60
Handling Rate Limits
async function rateLimitedRequest(endpoint, options = {}) {
const response = await fetch(`https://api.hixbe.com${endpoint}`, options);
if (response.status === 429) {
const retryAfter = response.headers.get('X-RateLimit-Retry-After');
if (retryAfter) {
await sleep(parseInt(retryAfter) * 1000);
return rateLimitedRequest(endpoint, options); // Retry once
}
}
return response;
}
Monitoring and Alerting
Error Tracking
class ErrorTracker {
constructor() {
this.errors = new Map();
}
trackError(error) {
const key = `${error.code}_${Date.now()}`;
this.errors.set(key, {
error,
timestamp: new Date(),
stack: error.stack
});
// Alert on critical errors
if (this.isCriticalError(error)) {
this.alertAdmin(error);
}
// Clean old errors (keep last 24 hours)
this.cleanup();
}
isCriticalError(error) {
const criticalCodes = ['INVALID_API_KEY', 'INTERNAL_SERVER_ERROR'];
return criticalCodes.includes(error.code);
}
alertAdmin(error) {
// Send alert to admin (email, Slack, etc.)
console.error('CRITICAL ERROR:', error);
}
cleanup() {
const oneDayAgo = Date.now() - (24 * 60 * 60 * 1000);
for (const [key, data] of this.errors) {
if (data.timestamp.getTime() < oneDayAgo) {
this.errors.delete(key);
}
}
}
}
Best Practices
- Always check the
successfield in responses - Implement proper error logging and monitoring
- Use exponential backoff for retries
- Implement idempotency for critical operations
- Monitor rate limit headers
- Handle both expected and unexpected errors
- Test error scenarios in sandbox
- Keep error messages user-friendly
Need Help?
Troubleshooting
Common error scenarios and solutions
Best Practices
Learn more integration best practices
Webhooks
Monitor errors with webhook notifications
Support
Get help with error handling