Skip to main content

Error Handling

The My Virtual Office API uses standard HTTP status codes to indicate the success or failure of requests. This guide explains the error responses you may encounter and how to handle them.

Error Response Format

All error responses follow a consistent JSON format:
{
  "error": "Error Type",
  "message": "Human-readable description of what went wrong"
}

HTTP Status Codes

Success Codes

CodeDescription
200OK - Request succeeded
201Created - Resource successfully created

Client Error Codes

CodeDescription
400Bad Request - Invalid request format or missing required fields
401Unauthorized - Missing or invalid API key
403Forbidden - Valid API key but insufficient permissions or limits reached
404Not Found - Resource doesn’t exist
409Conflict - Resource already exists (e.g., duplicate email)
429Too Many Requests - Rate limit exceeded

Server Error Codes

CodeDescription
500Internal Server Error - Something went wrong on our end
503Service Unavailable - API temporarily unavailable

Common Errors and Solutions

Authentication Errors (401)

{
  "error": "Unauthorized",
  "message": "API key is required. Provide it via X-API-Key header or Authorization Bearer token."
}
Solution: Include your API key in the request headers:
-H "X-API-Key: sk_live_your_api_key_here"
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}
Solution: Verify your API key is correct. Generate a new one from Settings > API Keys if needed.
{
  "error": "Unauthorized",
  "message": "API key has been revoked"
}
Solution: This API key has been disabled. Generate a new one from your dashboard.
{
  "error": "Unauthorized",
  "message": "API key has expired"
}
Solution: This API key has passed its expiration date. Generate a new one from your dashboard.

Validation Errors (400)

{
  "error": "Bad Request",
  "message": "body must have required property 'email'"
}
Solution: Ensure all required fields are included in your request body.
{
  "error": "Bad Request",
  "message": "body/email must match format \"email\""
}
Solution: Provide a valid email address in the correct format.

Business Logic Errors (403)

{
  "error": "Forbidden",
  "message": "Customer limit reached. Your plan allows 10 customers."
}
Solution: Upgrade your subscription to add more customers, or remove existing customers you no longer need.

Conflict Errors (409)

{
  "error": "Conflict",
  "message": "A customer with this email already exists"
}
Solution: Each customer must have a unique email address within your account. Use a different email or update the existing customer.

Best Practices

1. Always Check Status Codes

const response = await fetch('https://api.my-virtual-office.com/api/customers', {
  method: 'POST',
  headers: {
    'X-API-Key': apiKey,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(customerData),
});

if (!response.ok) {
  const error = await response.json();

  switch (response.status) {
    case 401:
      // Handle authentication error
      console.error('Authentication failed:', error.message);
      break;
    case 403:
      // Handle limit reached
      console.error('Limit reached:', error.message);
      break;
    case 409:
      // Handle duplicate
      console.error('Customer already exists:', error.message);
      break;
    default:
      console.error('API error:', error.message);
  }
  return;
}

const customer = await response.json();

2. Implement Retry Logic

For transient errors (5xx), implement retry with exponential backoff:
async function createCustomerWithRetry(data, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch('https://api.my-virtual-office.com/api/customers', {
        method: 'POST',
        headers: {
          'X-API-Key': apiKey,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      });

      if (response.status >= 500) {
        throw new Error(`Server error: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      if (attempt === maxRetries) throw error;

      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, attempt - 1) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

3. Log Errors for Debugging

Keep detailed logs of API errors to help with debugging:
if (!response.ok) {
  const error = await response.json();
  console.error({
    timestamp: new Date().toISOString(),
    endpoint: '/api/customers',
    method: 'POST',
    status: response.status,
    error: error.error,
    message: error.message,
    requestData: customerData,
  });
}

4. Handle Rate Limiting

If you receive a 429 error, wait before retrying:
if (response.status === 429) {
  const retryAfter = response.headers.get('Retry-After') || 60;
  await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
  // Retry the request
}

Need Help?

If you’re encountering errors that you can’t resolve, please contact our support team at hello@my-virtual-office.com with:
  • The endpoint you’re calling
  • The request body (with sensitive data removed)
  • The full error response
  • Your account email