Skip to main content

Error Response Format

When an error occurs, Vellosim API returns a JSON response with error details:
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description"
  },
  "statusCode": 400
}

Common Error Codes

Authentication Errors

Error CodeStatusDescriptionSolution
UNAUTHORIZED401Missing or invalid API keyCheck your API key and ensure it’s included in the Authorization header
FORBIDDEN403Valid key but insufficient permissionsContact support to upgrade your permissions
RATE_LIMIT_EXCEEDED429Too many requestsImplement rate limiting and retry with exponential backoff

Validation Errors

Error CodeStatusDescriptionSolution
INVALID_PARAMETERS400Missing or invalid request parametersReview the required parameters for the endpoint
INVALID_REGION_CODE400Invalid region code providedUse valid region codes from the regions endpoint
INVALID_PACKAGE_CODE400Package code doesn’t existVerify package code from packages endpoint

Business Logic Errors

Error CodeStatusDescriptionSolution
INSUFFICIENT_BALANCE400Wallet balance too lowTop up your wallet balance
PACKAGE_UNAVAILABLE400Package is temporarily unavailableTry a different package or retry later
ORDER_NOT_FOUND404Order ID doesn’t existVerify the order ID
DUPLICATE_ORDER409Order already existsCheck your order history

Server Errors

Error CodeStatusDescriptionSolution
INTERNAL_ERROR500Internal server errorRetry the request or contact support
SERVICE_UNAVAILABLE503Service temporarily unavailableWait and retry with exponential backoff

Error Handling Examples

Basic Error Handling

async function getPackages(regionCode: string, regionType: string) {
  try {
    const response = await fetch(
      `https://api.vellosim.com/api/esim/packages?regionCode=${regionCode}&regionType=${regionType}`,
      {
        headers: {
          'X-API-Key': `API_KEY}`,
          'Content-Type': 'application/json'
        }
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error.message);
    }

    return await response.json();
  } catch (error) {
    console.error('Failed to fetch packages:', error);
    throw error;
  }
}

Advanced Error Handling with Retry Logic

async function makeRequestWithRetry(
  url: string,
  options: RequestInit,
  maxRetries: number = 3
) {
  let lastError: Error;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      // Handle different error types
      if (!response.ok) {
        const error = await response.json();
        
        // Don't retry client errors (4xx)
        if (response.status >= 400 && response.status < 500) {
          throw new Error(error.error.message);
        }
        
        // Retry server errors (5xx) with exponential backoff
        if (response.status >= 500) {
          const delay = Math.pow(2, attempt) * 1000;
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      }
      
      return await response.json();
      
    } catch (error) {
      lastError = error as Error;
      
      // Don't retry on last attempt
      if (attempt === maxRetries - 1) {
        break;
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  throw lastError!;
}

User-Friendly Error Messages

Create a mapping for user-friendly error messages:
const ERROR_MESSAGES = {
  UNAUTHORIZED: 'Authentication failed. Please check your credentials.',
  INSUFFICIENT_BALANCE: 'Your account balance is too low. Please top up your wallet.',
  INVALID_PACKAGE_CODE: 'The selected package is not available. Please choose another.',
  RATE_LIMIT_EXCEEDED: 'Too many requests. Please wait a moment and try again.',
  PACKAGE_UNAVAILABLE: 'This package is temporarily unavailable. Please try another.',
  INTERNAL_ERROR: 'Something went wrong on our end. Please try again later.',
  SERVICE_UNAVAILABLE: 'Service is temporarily unavailable. Please try again later.'
};

function getUserFriendlyMessage(errorCode: string): string {
  return ERROR_MESSAGES[errorCode] || 'An unexpected error occurred. Please try again.';
}

// Usage
try {
  await purchaseEsim(packageCode);
} catch (error) {
  const message = getUserFriendlyMessage(error.code);
  showErrorToUser(message);
}

Validation Before API Calls

Validate data before making API requests to reduce errors:
function validatePurchaseRequest(data) {
  const errors = [];
  
  if (!data.packageCode) {
    errors.push('Package code is required');
  }
  
  if (!data.paymentMethod) {
    errors.push('Payment method is required');
  } else if (!['wallet', 'card'].includes(data.paymentMethod)) {
    errors.push('Invalid payment method');
  }
  
  if (!data.packageType) {
    errors.push('Package type is required');
  }
  
  if (errors.length > 0) {
    throw new Error(errors.join(', '));
  }
}

// Usage
try {
  validatePurchaseRequest(purchaseData);
  await purchaseEsim(purchaseData);
} catch (error) {
  handleValidationError(error);
}

Logging and Monitoring

Implement proper logging for debugging:
function logApiError(error, context) {
  console.error({
    timestamp: new Date().toISOString(),
    error: error.message,
    code: error.code,
    statusCode: error.statusCode,
    context: context,
    stack: error.stack
  });
  
  // Send to monitoring service (e.g., Sentry, DataDog)
  if (window.Sentry) {
    Sentry.captureException(error, {
      extra: context
    });
  }
}

Best Practices

For transient errors and rate limits, use exponential backoff to automatically retry failed requests with increasing delays.
Never retry 4xx errors (except 429) as they indicate client-side issues that won’t be resolved by retrying.
Log all errors with context to help debugging. Include request parameters, timestamps, and user identifiers (without sensitive data).
Don’t expose technical error messages to end users. Create friendly, actionable error messages instead.
Track error rates and patterns to identify issues early and improve your integration.
When APIs fail, provide fallback options or cached data when possible to maintain user experience.

Next Steps