API Error Handling

The Demi API uses conventional HTTP response codes to indicate success or failure.

Error Response Format

All errors return a JSON object with an error property:

{
  "error": {
    "statusCode": 400,
    "name": "BadRequestError",
    "message": "Customer name is required"
  }
}

HTTP Status Codes

Code Status Description
200 OK Request succeeded
201 Created Resource created successfully
400 Bad Request Invalid request parameters or body
401 Unauthorized Missing or invalid API key
403 Forbidden API key lacks required scope
404 Not Found Resource not found
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error (contact support)

Common Errors

401 Unauthorized

{
  "error": {
    "statusCode": 401,
    "message": "API key required. Provide X-API-Key header."
  }
}

Solution: Include your API key in the X-API-Key header.

403 Forbidden

{
  "error": {
    "statusCode": 403,
    "message": "Insufficient permissions"
  }
}

Solution: Your API key needs additional scopes. Generate a new key with the required scopes.

404 Not Found

{
  "error": {
    "statusCode": 404,
    "message": "Customer 12345 not found"
  }
}

Solution: Verify the resource ID exists and you have access to it.

Best Practices

  • Check status codes first - Handle different status codes appropriately
  • Log errors - Keep logs for debugging
  • Show user-friendly messages - Don't expose raw API errors to end users
  • Retry transient errors - 5xx errors may be temporary; retry with backoff
  • Don't retry 4xx errors - Fix the issue before retrying

Example: Error Handling

try {
  const response = await fetch('/api/v1/customers', {
    headers: { 'X-API-Key': apiKey }
  });

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

    switch (response.status) {
      case 401:
        throw new Error('Invalid API key');
      case 403:
        throw new Error('Permission denied');
      case 404:
        throw new Error('Resource not found');
      case 429:
        // Wait and retry
        const retryAfter = response.headers.get('Retry-After');
        await sleep(retryAfter * 1000);
        return retry();
      default:
        throw new Error(error.error?.message || 'API error');
    }
  }

  return response.json();
} catch (error) {
  console.error('API Error:', error.message);
  throw error;
}