Loyalty.lt
API Basics

Error Handling

How the Loyalty.lt API reports errors and how to handle them

Error Handling

The API uses conventional HTTP status codes: 2xx for success, 4xx for a request problem, 5xx for a server problem. Every response — success or error — uses the same envelope, and every error carries a unique request_id for support.

Response envelope

Success

{
  "success": true,
  "code": 200,
  "message": "Operation completed successfully",
  "data": { }
}

Error

{
  "success": false,
  "code": 1004,
  "message": "API key and secret are required.",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Note

code is a numeric application code (e.g. 1004), not a string. Branch on the HTTP status for control flow and show message to developers; include request_id when contacting support.

Validation error (HTTP 422)

When input fails validation the response includes an errors object keyed by field:

{
  "success": false,
  "code": 422,
  "message": "The given data was invalid.",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "errors": {
    "email": ["The email field is required."],
    "points": ["The points must be a positive integer."]
  }
}

HTTP status codes

CodeMeaning
200 / 201 / 204Success (OK / Created / No Content)
400Malformed request
401Missing or invalid authentication
403Authenticated but not allowed
404Resource not found
422Validation failed (see errors)
429Too many requests — back off and retry
500 / 502 / 503 / 504Server-side error — retry with backoff

Handling errors

Branch on the HTTP status, read message/errors, and retry 429/5xx with exponential backoff. Do not retry 4xx client errors other than 429.

const axios = require('axios');

async function makeAPICall() {
  try {
    const res = await axios.get('https://staging-api.loyalty.lt/en/shop/loyalty-cards', {
      headers: {
        'X-API-Key': process.env.LOYALTY_API_KEY,
        'X-API-Secret': process.env.LOYALTY_API_SECRET,
      },
    });
    return res.data;
  } catch (error) {
    const { status, data } = error.response ?? {};
    switch (status) {
      case 401:
        console.error('Authentication failed:', data?.message);
        break;
      case 422:
        for (const [field, messages] of Object.entries(data?.errors ?? {})) {
          console.error(`- ${field}: ${messages.join(', ')}`);
        }
        break;
      case 429:
        // throttled — retry with exponential backoff
        break;
      default:
        console.error('API error:', data?.message ?? error.message);
    }
    throw error;
  }
}

Exponential backoff

async function exponentialBackoff(fn, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const status = error.response?.status;
      const retryable = status === 429 || (status >= 500 && status <= 599);
      if (!retryable || attempt === maxRetries) throw error;
      const delay = Math.min(1000 * 2 ** attempt, 10000) + Math.random() * 1000;
      await new Promise((r) => setTimeout(r, delay));
    }
  }
}

Log with context

function logAPIError(error, context) {
  console.error('API Error:', JSON.stringify({
    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,
  }, null, 2));
}

Testing error responses

# 401 — missing credentials
curl -X GET "https://staging-api.loyalty.lt/en/shop/loyalty-cards"

# 401 — invalid key
curl -X GET "https://staging-api.loyalty.lt/en/shop/loyalty-cards" \
  -H "X-API-Key: invalid_key" -H "X-API-Secret: invalid_secret"

Support

Request ID

Always include the request_id from the error response when contacting support.

Check for known issues and maintenance windows.

Tip

When reporting an error, include the request_id, timestamp, endpoint, and the request/response bodies (excluding secrets).

On this page