Error Handling
This guide covers all API error codes, response formats, and best practices for handling errors in your Torque API integration.
๐ Quick Startโ
Basic Error Handlingโ
try {
const response = await fetch('https://api.torque.fi/v1/checkout/generate-link', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
const error = await response.json();
throw new TorqueError(error.error, error.code, error.details);
}
return await response.json();
} catch (error) {
if (error instanceof TorqueError) {
console.error('Torque API Error:', error.message, error.code);
// Handle specific error types
switch (error.code) {
case 'AUTH_001':
// Handle authentication error
break;
case 'CHECKOUT_001':
// Handle checkout error
break;
default:
// Handle unknown error
}
} else {
console.error('Network or other error:', error);
}
}
Error Response Formatโ
Standard Error Responseโ
All API errors follow this consistent format:
{
"success": false,
"error": "Human-readable error message",
"code": "ERROR_CODE",
"details": {
"field": "Specific field that caused the error",
"message": "Detailed error description",
"value": "Value that caused the error"
},
"timestamp": "2024-01-15T10:00:00Z",
"requestId": "req_abc123"
}
Error Response Fieldsโ
success
: Alwaysfalse
for errorserror
: Human-readable error messagecode
: Machine-readable error codedetails
: Additional error context (optional)timestamp
: When the error occurredrequestId
: Unique request identifier for support
HTTP Status Codesโ
Client Errors (4xx)โ
400 Bad Request
: Invalid request data or parameters401 Unauthorized
: Missing or invalid authentication403 Forbidden
: Insufficient permissions404 Not Found
: Resource not found409 Conflict
: Resource conflict or duplicate422 Unprocessable Entity
: Validation errors429 Too Many Requests
: Rate limit exceeded
Server Errors (5xx)โ
500 Internal Server Error
: Unexpected server error502 Bad Gateway
: Upstream service error503 Service Unavailable
: Service temporarily unavailable504 Gateway Timeout
: Request timeout
๐ Authentication Errorsโ
AUTH_001: Invalid or Missing API Keyโ
Status: 401 Unauthorized
{
"success": false,
"error": "Invalid or missing API key",
"code": "AUTH_001",
"details": {
"field": "Authorization",
"message": "API key is required in Authorization header"
}
}
Causes:
- Missing
Authorization
header - Invalid API key format
- Expired or revoked API key
Solutions:
// Ensure proper header format
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
// Verify API key is valid
const testResponse = await fetch('https://api.torque.fi/v1/auth/test', {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
AUTH_002: Insufficient Permissionsโ
Status: 403 Forbidden
{
"success": false,
"error": "Insufficient permissions for this endpoint",
"code": "AUTH_002",
"details": {
"required": "business:write",
"current": "business:read"
}
}
Causes:
- API key doesn't have required permissions
- Business account is suspended
- Endpoint requires elevated access
Solutions:
- Check API key permissions in dashboard
- Contact support for elevated access
- Verify business account status
AUTH_003: API Key Expiredโ
Status: 401 Unauthorized
{
"success": false,
"error": "API key has expired",
"code": "AUTH_003",
"details": {
"expiredAt": "2024-01-15T00:00:00Z"
}
}
Solutions:
- Generate new API key
- Update applications with new key
- Set up key rotation schedule
๐ Checkout Errorsโ
CHECKOUT_001: Invalid Cart Dataโ
Status: 400 Bad Request
{
"success": false,
"error": "Invalid cart data",
"code": "CHECKOUT_001",
"details": {
"field": "cart.items",
"message": "At least one item is required",
"value": []
}
}
Common Issues:
- Empty cart items array
- Missing required item fields
- Invalid price format
Solutions:
// Ensure cart has items
const cart = {
items: [
{
productId: 'prod_1',
quantity: 1,
price: 29.99
}
]
};
// Validate before sending
if (!cart.items || cart.items.length === 0) {
throw new Error('Cart must contain at least one item');
}
CHECKOUT_002: Invalid Customer Dataโ
Status: 400 Bad Request
{
"success": false,
"error": "Invalid customer data",
"code": "CHECKOUT_002",
"details": {
"field": "customerData.email",
"message": "Valid email address is required",
"value": "invalid-email"
}
}
Common Issues:
- Invalid email format
- Missing required fields
- Invalid phone number format
Solutions:
// Validate customer data
const customerData = {
email: 'customer@example.com', // Required
firstName: 'John', // Required
lastName: 'Doe' // Required
};
// Email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(customerData.email)) {
throw new Error('Invalid email format');
}
CHECKOUT_003: Business Not Foundโ
Status: 404 Not Found
{
"success": false,
"error": "Business not found",
"code": "CHECKOUT_003",
"details": {
"businessId": "business_999",
"message": "Business with this ID does not exist"
}
}
Solutions:
- Verify business ID is correct
- Check business account is active
- Use business ID from dashboard
CHECKOUT_004: Checkout Session Expiredโ
Status: 410 Gone
{
"success": false,
"error": "Checkout session has expired",
"code": "CHECKOUT_004",
"details": {
"sessionId": "session_abc123",
"expiredAt": "2024-01-15T10:30:00Z"
}
}
Solutions:
- Generate new checkout link
- Reduce session expiry time
- Implement session refresh logic
Webhook Errorsโ
WEBHOOK_001: Invalid Signatureโ
Status: 401 Unauthorized
{
"success": false,
"error": "Invalid webhook signature",
"code": "WEBHOOK_001",
"details": {
"field": "X-Torque-Signature",
"message": "Signature verification failed"
}
}
Solutions:
// Verify webhook signature
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
WEBHOOK_002: URL Unreachableโ
Status: 400 Bad Request
{
"success": false,
"error": "Webhook URL is unreachable",
"code": "WEBHOOK_002",
"details": {
"url": "https://example.com/webhooks",
"message": "HTTP request failed with status 404"
}
}
Solutions:
- Verify webhook endpoint is accessible
- Check HTTPS is enabled
- Test endpoint manually
WEBHOOK_003: Processing Timeoutโ
Status: 408 Request Timeout
{
"success": false,
"error": "Webhook processing timeout",
"code": "WEBHOOK_003",
"details": {
"timeout": 30000,
"message": "Response not received within 30 seconds"
}
}
Solutions:
- Process webhooks asynchronously
- Return quickly and process in background
- Use queue systems for heavy processing
๐ Analytics Errorsโ
ANALYTICS_001: Invalid Date Rangeโ
Status: 400 Bad Request
{
"success": false,
"error": "Invalid date range",
"code": "ANALYTICS_001",
"details": {
"field": "endDate",
"message": "End date must be after start date",
"value": "2024-01-01T00:00:00Z"
}
}
Solutions:
// Validate date range
const startDate = new Date('2024-01-01');
const endDate = new Date('2024-01-31');
if (endDate <= startDate) {
throw new Error('End date must be after start date');
}
// Use ISO 8601 format
const params = {
startDate: startDate.toISOString(),
endDate: endDate.toISOString()
};
ANALYTICS_002: Export Failedโ
Status: 500 Internal Server Error
{
"success": false,
"error": "Export generation failed",
"code": "ANALYTICS_002",
"details": {
"exportId": "export_abc123",
"message": "Failed to process large dataset"
}
}
Solutions:
- Reduce date range size
- Use smaller time periods
- Contact support for large exports
โก Rate Limiting Errorsโ
RATE_001: Rate Limit Exceededโ
Status: 429 Too Many Requests
{
"success": false,
"error": "Rate limit exceeded",
"code": "RATE_001",
"details": {
"limit": 1000,
"reset": 1642233600,
"retryAfter": 60
}
}
Solutions:
// Implement exponential backoff
async function makeRequestWithRetry() {
try {
return await makeApiRequest();
} catch (error) {
if (error.code === 'RATE_001') {
const retryAfter = error.details.retryAfter || 60;
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return makeRequestWithRetry();
}
throw error;
}
}
// Check rate limit headers
const response = await fetch('/api/endpoint');
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
if (parseInt(remaining) < 10) {
// Implement rate limiting logic
await delay(1000);
}
๐ Retry Strategiesโ
Exponential Backoffโ
class TorqueClient {
constructor(apiKey, options = {}) {
this.apiKey = apiKey;
this.maxRetries = options.maxRetries || 3;
this.baseDelay = options.baseDelay || 1000;
}
async makeRequest(endpoint, options = {}) {
let lastError;
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
const response = await fetch(endpoint, {
...options,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new TorqueError(error.error, error.code, error.details);
}
// Retry server errors (5xx) and rate limits
if (response.status >= 500 || response.status === 429) {
throw new Error(`HTTP ${response.status}: ${error.error}`);
}
}
return await response.json();
} catch (error) {
lastError = error;
if (attempt === this.maxRetries) {
break;
}
// Calculate delay with exponential backoff
const delay = this.baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
}
Circuit Breaker Patternโ
class CircuitBreaker {
constructor(failureThreshold = 5, resetTimeout = 60000) {
this.failureThreshold = failureThreshold;
this.resetTimeout = resetTimeout;
this.failureCount = 0;
this.lastFailureTime = null;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
}
async execute(fn) {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailureTime > this.resetTimeout) {
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.failureThreshold) {
this.state = 'OPEN';
}
}
}
// Usage
const circuitBreaker = new CircuitBreaker();
const client = new TorqueClient(apiKey);
const result = await circuitBreaker.execute(() =>
client.makeRequest('/api/endpoint')
);
๐ Error Loggingโ
Structured Error Loggingโ
class ErrorLogger {
constructor() {
this.logger = console; // Replace with your logging service
}
logError(error, context = {}) {
const logEntry = {
timestamp: new Date().toISOString(),
level: 'ERROR',
error: {
message: error.message,
code: error.code,
details: error.details
},
context: {
endpoint: context.endpoint,
requestId: context.requestId,
userId: context.userId,
...context
}
};
this.logger.error(JSON.stringify(logEntry));
}
logApiError(response, context = {}) {
const error = {
status: response.status,
statusText: response.statusText,
url: response.url,
...context
};
this.logger.error('API Error:', error);
}
}
// Usage
const errorLogger = new ErrorLogger();
try {
const response = await client.makeRequest('/api/endpoint');
return response;
} catch (error) {
errorLogger.logError(error, {
endpoint: '/api/endpoint',
requestId: 'req_123',
userId: 'user_456'
});
throw error;
}
๐งช Testing Error Handlingโ
Error Simulationโ
// Test error handling with mock responses
class MockTorqueAPI {
constructor() {
this.errorMode = false;
this.errorCode = 'AUTH_001';
}
setErrorMode(enabled, code = 'AUTH_001') {
this.errorMode = enabled;
this.errorCode = code;
}
async makeRequest(endpoint) {
if (this.errorMode) {
const errorResponses = {
'AUTH_001': { status: 401, error: 'Invalid API key' },
'CHECKOUT_001': { status: 400, error: 'Invalid cart data' },
'RATE_001': { status: 429, error: 'Rate limit exceeded' }
};
const error = errorResponses[this.errorCode];
throw new TorqueError(error.error, this.errorCode);
}
return { success: true, data: 'Mock response' };
}
}
// Test error handling
const mockAPI = new MockTorqueAPI();
// Test authentication error
mockAPI.setErrorMode(true, 'AUTH_001');
try {
await mockAPI.makeRequest('/api/endpoint');
} catch (error) {
console.log('Handled auth error:', error.code);
}
// Test rate limiting
mockAPI.setErrorMode(true, 'RATE_001');
try {
await mockAPI.makeRequest('/api/endpoint');
} catch (error) {
console.log('Handled rate limit error:', error.code);
}
Next Stepsโ
- Data Types: Understand API data structures
- Business Dashboard: Monitor errors in your dashboard
- Support Resources: Get help with specific errors
- Platform Integrations: Handle errors in platform integrations
Need help with specific errors? Check our error troubleshooting guide or contact support at hello@torque.fi.