Error Handling
The Loyalty.lt API uses conventional HTTP response codes to indicate the success or failure of an API request. In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that failed given the information provided, and codes in the 5xx range indicate an error with our servers.
All error responses include a detailed error message and unique request ID to help with debugging and support.
Response Structure
Success Response
{
"success" : true ,
"code" : 200 ,
"request_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"message" : "Operation completed successfully" ,
"data" : {
// Response data here
}
}
Error Response
{
"success" : false ,
"code" : 400 ,
"request_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"message" : "Validation failed" ,
"errors" : [
{
"field" : "email" ,
"message" : "Email address is required" ,
"code" : "REQUIRED_FIELD"
}
]
}
HTTP Status Codes
2xx Success
Code Status Description 200 OK Request succeeded 201 Created Resource was successfully created 202 Accepted Request accepted for processing 204 No Content Request succeeded with no response body
4xx Client Errors
400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 422 Validation Error 429 Rate Limited The request was unacceptable, often due to missing or invalid parameters. {
"success" : false ,
"code" : 400 ,
"request_id" : "req_123" ,
"message" : "Invalid request parameters" ,
"errors" : [
{
"field" : "points" ,
"message" : "Points must be a positive integer" ,
"code" : "INVALID_VALUE"
}
]
}
Common Causes:
Invalid JSON in request body
Missing required parameters
Invalid parameter types or formats
Request body too large
5xx Server Errors
Code Status Description 500 Internal Server Error Something went wrong on our end 502 Bad Gateway Invalid response from upstream server 503 Service Unavailable Service temporarily overloaded or down 504 Gateway Timeout Request timed out
Error Codes
Each error includes a specific error code for programmatic handling:
Authentication Errors
INVALID_CREDENTIALS
- API key or secret is invalid
EXPIRED_TOKEN
- JWT token has expired
MISSING_AUTHENTICATION
- No authentication provided
INVALID_TOKEN_FORMAT
- Malformed JWT token
Authorization Errors
INSUFFICIENT_PERMISSIONS
- Lacking required permissions
ACCESS_DENIED
- Resource access denied
IP_NOT_WHITELISTED
- IP address not allowed
SCOPE_INSUFFICIENT
- API key scope limitations
Validation Errors
REQUIRED_FIELD
- Required field is missing
INVALID_VALUE
- Field value is invalid
DUPLICATE_VALUE
- Value already exists
INVALID_FORMAT
- Field format is incorrect
OUT_OF_RANGE
- Value outside allowed range
Business Logic Errors
INSUFFICIENT_BALANCE
- Not enough points/credits
RESOURCE_NOT_FOUND
- Requested resource doesn’t exist
INVALID_STATE
- Operation not allowed in current state
QUOTA_EXCEEDED
- Usage quota exceeded
EXPIRED_OFFER
- Offer or coupon has expired
Rate Limiting Errors
RATE_LIMIT_EXCEEDED
- Too many requests
DAILY_QUOTA_EXCEEDED
- Daily API quota reached
CONCURRENT_LIMIT_EXCEEDED
- Too many concurrent requests
Error Handling Best Practices
Implement Robust Error Handling
const axios = require ( 'axios' );
async function makeAPICall () {
try {
const response = await axios . post ( 'https://staging-api.loyalty.lt/api/customers' , {
email: 'customer@example.com' ,
first_name: 'John'
}, {
headers: {
'X-API-Key' : process . env . LOYALTY_API_KEY ,
'X-API-Secret' : process . env . LOYALTY_API_SECRET
}
});
return response . data ;
} catch ( error ) {
if ( error . response ) {
// API returned an error response
const { status , data } = error . response ;
switch ( status ) {
case 400 :
console . error ( 'Bad Request:' , data . message );
break ;
case 401 :
console . error ( 'Authentication failed:' , data . message );
// Refresh credentials or redirect to login
break ;
case 422 :
console . error ( 'Validation errors:' );
data . errors . forEach ( err => {
console . error ( `- ${ err . field } : ${ err . message } ` );
});
break ;
case 429 :
console . error ( 'Rate limited. Retry after:' , error . response . headers [ 'retry-after' ]);
// Implement exponential backoff
break ;
default :
console . error ( 'API Error:' , data . message );
}
} else if ( error . request ) {
// Network error
console . error ( 'Network error:' , error . message );
} else {
// Other error
console . error ( 'Error:' , error . message );
}
throw error ;
}
}
Implement Exponential Backoff
For rate limiting and server errors, implement exponential backoff:
async function exponentialBackoff ( fn , maxRetries = 3 ) {
for ( let attempt = 0 ; attempt <= maxRetries ; attempt ++ ) {
try {
return await fn ();
} catch ( error ) {
if ( error . response ?. status === 429 || error . response ?. status >= 500 ) {
if ( attempt === maxRetries ) throw error ;
const delay = Math . min ( 1000 * Math . pow ( 2 , attempt ), 10000 );
const jitter = Math . random () * 1000 ;
await new Promise ( resolve => setTimeout ( resolve , delay + jitter ));
} else {
throw error ;
}
}
}
}
Log Errors with Context
Always log errors with sufficient context for debugging:
function logAPIError ( error , context ) {
const logData = {
timestamp: new Date (). toISOString (),
context ,
request_id: error . response ?. data ?. request_id ,
status: error . response ?. status ,
message: error . response ?. data ?. message ,
errors: error . response ?. data ?. errors
};
console . error ( 'API Error:' , JSON . stringify ( logData , null , 2 ));
}
Common Error Scenarios
Insufficient Points Balance
{
"success" : false ,
"code" : 422 ,
"message" : "Cannot redeem points" ,
"errors" : [
{
"field" : "points" ,
"message" : "Customer has 150 points but 200 points requested" ,
"code" : "INSUFFICIENT_BALANCE" ,
"meta" : {
"available_points" : 150 ,
"requested_points" : 200
}
}
]
}
Handling:
if ( error . response ?. data ?. errors ?.[ 0 ]?. code === 'INSUFFICIENT_BALANCE' ) {
const available = error . response . data . errors [ 0 ]. meta . available_points ;
console . log ( `Customer only has ${ available } points available` );
// Update UI to show available points
}
Expired Offers
{
"success" : false ,
"code" : 422 ,
"message" : "Cannot redeem offer" ,
"errors" : [
{
"field" : "offer_id" ,
"message" : "Offer expired on 2024-01-15" ,
"code" : "EXPIRED_OFFER" ,
"meta" : {
"expired_at" : "2024-01-15T23:59:59Z"
}
}
]
}
Duplicate Customer Registration
{
"success" : false ,
"code" : 422 ,
"message" : "Customer already exists" ,
"errors" : [
{
"field" : "email" ,
"message" : "Email address is already registered" ,
"code" : "DUPLICATE_VALUE" ,
"meta" : {
"existing_customer_id" : "cust_123"
}
}
]
}
Webhooks Error Handling
When receiving webhooks, always return appropriate HTTP status codes:
app . post ( '/webhooks/loyalty' , ( req , res ) => {
try {
// Verify webhook signature
if ( ! verifyWebhookSignature ( req . body , req . headers [ 'x-signature' ])) {
return res . status ( 401 ). json ({ error: 'Invalid signature' });
}
// Process webhook
processLoyaltyEvent ( req . body );
// Return success
res . status ( 200 ). json ({ received: true });
} catch ( error ) {
console . error ( 'Webhook processing failed:' , error );
// Return 5xx to trigger retry
res . status ( 500 ). json ({ error: 'Processing failed' });
}
});
Testing Error Scenarios
Simulate Errors in Staging
Use these techniques to test error handling:
# Test validation errors
curl -X POST "https://staging-api.loyalty.lt/api/customers" \
-H "X-API-Key: your_key" \
-H "X-API-Secret: your_secret" \
-d '{"email": "invalid-email"}'
# Test authentication errors
curl -X GET "https://staging-api.loyalty.lt/api/customers" \
-H "X-API-Key: invalid_key"
# Test rate limiting (make many rapid requests)
for i in { 1..100} ; do
curl -X GET "https://staging-api.loyalty.lt/api/customers"
done
Error Monitoring
Set up monitoring for common error patterns:
// Monitor error rates
function trackAPIError ( error ) {
const metrics = {
error_type: error . response ?. data ?. errors ?.[ 0 ]?. code || 'UNKNOWN' ,
status_code: error . response ?. status ,
endpoint: error . config ?. url ,
timestamp: Date . now ()
};
// Send to monitoring service
analytics . track ( 'api_error' , metrics );
}
Support & Debugging
When reporting errors, include the request ID, timestamp, endpoint URL, and request/response bodies (excluding sensitive data).