DocsAdvanced guidesError Handling

Error handling

When integrating with lomi., it’s essential to handle errors gracefully to provide a smooth payment experience for your customers. lomi. uses conventional HTTP response codes and returns meaningful error messages that you can use to troubleshoot issues and inform your customers about the status of their transactions.

Refer to the Error Reference for a detailed list of status codes and common error responses.

Error response format

All API errors follow a consistent JSON structure:

Example error response structure
{
  "error": {
    "message": "A human-readable description of the error.",
    "details": "Optional: Additional context or structured data about the error."
    // Specific error types might include additional fields like "code" or validation details
  }
}

Handling common error types

Validation errors (HTTP 400)

These occur when the request data is invalid or missing required fields.

Handling validation errors (example)
import { LomiSDK, LomiApiError } from '@lomi/sdk'; // Assuming SDK exports error type
 
const lomi = new LomiSDK({ apiKey: process.env.LOMI_API_KEY! });
 
try {
  const session = await lomi.checkoutSessions.create({
    amount: -100,  // Invalid: must be positive
    currency_code: 'INVALID',  // Invalid enum value
    allowed_providers: []  // Invalid: must not be empty
    // Missing required fields like success_url, cancel_url
  });
} catch (error) {
  if (error instanceof LomiApiError && error.statusCode === 400) {
    console.error('Validation failed:', error.message);
    // Log or display specific details if available in error.details
    console.error('Details:', error.details);
    // Inform the user about the specific input issues
  } else {
    // Handle other types of errors
    console.error('An unexpected error occurred:', error);
  }
}

Authentication errors (HTTP 401)

These occur when the LOMI_API_KEY is missing, invalid, or doesn’t have the necessary permissions.

Handling authentication errors (example)
import { LomiSDK, LomiApiError } from '@lomi/sdk';
 
const lomi = new LomiSDK({ apiKey: 'invalid-key' });
 
try {
  await lomi.providers.list(); // Example request
} catch (error) {
  if (error instanceof LomiApiError && error.statusCode === 401) {
    console.error('Authentication failed:', error.message);
    // Check common issues:
    if (!process.env.LOMI_API_KEY) {
      console.error('Suggestion: LOMI_API_KEY environment variable might be missing.');
    } else {
      console.error('Suggestion: Verify the LOMI_API_KEY is correct and active.');
    }
  } else {
    console.error('An unexpected error occurred:', error);
  }
}

Rate limit errors (HTTP 429)

Occur when you exceed the allowed number of requests within a given time window (e.g., 100 requests per 15 minutes).

Handling rate limit errors (example)
import { LomiSDK, LomiApiError } from '@lomi/sdk';
 
const lomi = new LomiSDK({ apiKey: process.env.LOMI_API_KEY! });
 
async function makeRequestWithRateLimitHandling() {
  try {
    const response = await lomi.providers.list();
    // Process successful response
  } catch (error) {
    if (error instanceof LomiApiError && error.statusCode === 429) {
      console.warn('Rate limit exceeded. Retrying after delay...');
      // Extract Retry-After header if available (implementation depends on SDK/fetch)
      const retryAfterSeconds = error.headers?.['retry-after'] ? parseInt(error.headers['retry-after'], 10) : 60;
      await new Promise(resolve => setTimeout(resolve, retryAfterSeconds * 1000));
      // Retry the request (implement proper retry logic, see below)
      // await makeRequestWithRateLimitHandling();
    } else {
      console.error('An unexpected error occurred:', error);
    }
  }
}

Server errors (HTTP 5xx)

These indicate a problem on lomi.’s side. These should be rare. It’s generally safe to retry these requests after a delay.

Best practices

  1. Graceful Degradation:

    • Anticipate potential API failures.
    • Provide user-friendly feedback instead of raw error messages.
    • Have fallback mechanisms if a critical operation fails (e.g., allow manual order processing).
    • Log detailed error information (including request IDs if available) on your server for debugging, but don’t expose sensitive details to the client.
  2. Retry Strategy (with Exponential Backoff & Jitter): Implement a retry mechanism for network errors, rate limiting (429), and server errors (5xx). Avoid retrying client errors (4xx other than 429) as they usually require correcting the request.

    Implementing retries with exponential backoff
    async function withRetry<T>(asyncFn: () => Promise<T>, maxRetries = 3, initialDelayMs = 1000): Promise<T> {
      let attempts = 0;
      while (true) {
        try {
          return await asyncFn();
        } catch (error: any) {
          attempts++;
          const isRetryable = error instanceof LomiApiError && (error.statusCode === 429 || error.statusCode >= 500);
     
          if (!isRetryable || attempts >= maxRetries) {
            // Don't retry client errors (except 429) or if max retries exceeded
            throw error;
          }
     
          // Calculate delay with exponential backoff and jitter
          const delay = initialDelayMs * Math.pow(2, attempts - 1);
          const jitter = delay * 0.2 * Math.random(); // Add +/- 10% jitter
          const waitTime = Math.max(100, delay + jitter); // Ensure minimum wait
     
          console.warn(`Attempt ${attempts} failed. Retrying in ${waitTime.toFixed(0)}ms...`, error.message);
          await new Promise(resolve => setTimeout(resolve, waitTime));
        }
      }
    }
     
    // Example usage:
    // const providers = await withRetry(() => lomi.providers.list());
  3. Error Monitoring:

    • Use an application monitoring service (e.g., Sentry, Datadog) to track errors in production.
    • Monitor error rates and patterns to identify systemic issues.
    • Set up alerts for critical errors or unusual spikes in error rates.

Next steps