Skip to main content

Error Response Format

All API errors follow a consistent format to make error handling predictable and reliable.

Standard Error Structure

{
  "status": 400,
  "message": "Invalid job configuration",
  "code": "BAD_REQUEST",
  "request_id": "req_a1b2c3d4"
}
status
integer
required
HTTP status code (400, 401, 403, 404, 500, etc.).
message
string
required
Human-readable error description explaining what went wrong.
code
string
required
Machine-readable error code for programmatic error handling.
request_id
string
Unique identifier for this request. Include this when contacting support or reporting issues.

HTTP Status Codes

The API uses standard HTTP status codes to indicate the outcome of requests:

Success Codes (2xx)

200 OK
success
Request succeeded. Response body contains the requested data.
201 Created
success
Resource created successfully. Response body contains the new resource.
204 No Content
success
Request succeeded with no response body (typically for DELETE operations).

Client Error Codes (4xx)

400 Bad Request
error
The request is malformed or contains invalid parameters.
401 Unauthorized
error
Authentication is required or the provided credentials are invalid.
403 Forbidden
error
Authentication succeeded but the user lacks permission for this operation.
404 Not Found
error
The requested resource does not exist.
405 Method Not Allowed
error
The HTTP method is not supported for this endpoint.
409 Conflict
error
The request conflicts with the current state (e.g., duplicate resource).
422 Unprocessable Entity
error
Request syntax is valid but contains semantic errors.
429 Too Many Requests
error
Rate limit exceeded. Check the Retry-After header.

Server Error Codes (5xx)

500 Internal Server Error
error
An unexpected error occurred on the server.
503 Service Unavailable
error
The service is temporarily unavailable (maintenance, overload, etc.).

Error Codes

The code field provides a machine-readable error identifier for programmatic handling.

Client Error Codes

Error CodeHTTP StatusDescription
BAD_REQUEST400Malformed request or invalid parameters
UNAUTHORISED401Missing or invalid authentication
FORBIDDEN403Insufficient permissions
NOT_FOUND404Resource does not exist
METHOD_NOT_ALLOWED405HTTP method not supported
CONFLICT409Resource conflict
VALIDATION_ERROR422Request validation failed
RATE_LIMIT_EXCEEDED429Too many requests

Server Error Codes

Error CodeHTTP StatusDescription
INTERNAL_ERROR500Unexpected server error
SERVICE_UNAVAILABLE503Service temporarily unavailable
DATABASE_ERROR500Database connection or query error

Common Error Scenarios

Authentication Errors

Missing Authorization Header:
{
  "status": 401,
  "message": "Authentication required",
  "code": "UNAUTHORISED",
  "request_id": "req_a1b2c3d4"
}
Invalid or Expired Token:
{
  "status": 401,
  "message": "Invalid or expired token",
  "code": "UNAUTHORISED",
  "request_id": "req_a1b2c3d4"
}
Insufficient Permissions:
{
  "status": 403,
  "message": "Insufficient permissions for this operation",
  "code": "FORBIDDEN",
  "request_id": "req_a1b2c3d4"
}

Validation Errors

Missing Required Fields:
{
  "status": 400,
  "message": "user_id and email are required",
  "code": "BAD_REQUEST",
  "request_id": "req_a1b2c3d4"
}
Invalid Field Values:
{
  "status": 400,
  "message": "full_name must be 120 characters or fewer",
  "code": "BAD_REQUEST",
  "request_id": "req_a1b2c3d4"
}
Invalid JSON:
{
  "status": 400,
  "message": "Invalid JSON request body",
  "code": "BAD_REQUEST",
  "request_id": "req_a1b2c3d4"
}

Resource Errors

Resource Not Found:
{
  "status": 404,
  "message": "Job not found",
  "code": "NOT_FOUND",
  "request_id": "req_a1b2c3d4"
}
Method Not Allowed:
{
  "status": 405,
  "message": "Method not allowed",
  "code": "METHOD_NOT_ALLOWED",
  "request_id": "req_a1b2c3d4"
}

Rate Limiting

Too Many Requests:
{
  "status": 429,
  "message": "Too many requests, please retry shortly",
  "code": "RATE_LIMIT_EXCEEDED",
  "request_id": "req_a1b2c3d4"
}
When rate limited, check the Retry-After header:
HTTP/1.1 429 Too Many Requests
Retry-After: 3
Content-Type: application/json

Database Errors

Database Connection Issues:
{
  "status": 500,
  "message": "Database connection failed",
  "code": "DATABASE_ERROR",
  "request_id": "req_a1b2c3d4"
}
Database Saturation:
{
  "status": 429,
  "message": "Database is busy, please retry shortly",
  "code": "RATE_LIMIT_EXCEEDED",
  "request_id": "req_a1b2c3d4"
}

Server Errors

Internal Server Error:
{
  "status": 500,
  "message": "An unexpected error occurred",
  "code": "INTERNAL_ERROR",
  "request_id": "req_a1b2c3d4"
}
Service Unavailable:
{
  "status": 503,
  "message": "Service temporarily unavailable",
  "code": "SERVICE_UNAVAILABLE",
  "request_id": "req_a1b2c3d4"
}

Error Handling Best Practices

Check Status Codes

Always check the HTTP status code before parsing the response:
const response = await fetch(url, options);

if (!response.ok) {
  const error = await response.json();
  console.error(`Error ${error.code}: ${error.message}`);
  // Handle error based on status code
  if (response.status === 401) {
    // Refresh token or redirect to login
  } else if (response.status === 429) {
    // Wait and retry
  }
  return;
}

const data = await response.json();

Handle Specific Error Codes

Use the code field for programmatic error handling:
try {
  const response = await apiRequest(url, options);
  return response.data;
} catch (error) {
  switch (error.code) {
    case 'UNAUTHORISED':
      await refreshToken();
      return retry(url, options);
    
    case 'RATE_LIMIT_EXCEEDED':
      const retryAfter = error.retryAfter || 3;
      await sleep(retryAfter * 1000);
      return retry(url, options);
    
    case 'NOT_FOUND':
      // Resource doesn't exist
      return null;
    
    default:
      // Log unexpected errors
      console.error('Unexpected API error:', error);
      throw error;
  }
}

Implement Retry Logic

For transient errors (429, 503), implement exponential backoff:
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After') || (2 ** i);
        await sleep(retryAfter * 1000);
        continue;
      }
      
      if (response.status === 503 && i < maxRetries - 1) {
        await sleep(2 ** i * 1000);
        continue;
      }
      
      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await sleep(2 ** i * 1000);
    }
  }
}

Log Request IDs

Always log the request_id when errors occur:
catch (error) {
  console.error('API request failed:', {
    code: error.code,
    message: error.message,
    request_id: error.request_id,
    url: url
  });
}

Validate Input Client-Side

Validate input before sending requests to avoid unnecessary API calls:
function validateJobRequest(data) {
  if (!data.domain) {
    throw new Error('Domain is required');
  }
  
  if (data.options?.max_pages && data.options.max_pages < 1) {
    throw new Error('max_pages must be positive');
  }
  
  // Additional validation...
}

Debugging Errors

Include Request ID in Support Requests

When reporting issues, always include the request_id:
I received a 500 error when creating a job.
Request ID: req_a1b2c3d4
Timestamp: 2026-03-03T12:34:56Z

Check Server Logs

For 5xx errors, the server logs contain detailed context:
  • Request method and path
  • User ID and organisation ID
  • Error stack trace
  • Request ID for correlation

Monitor Error Rates

Track error rates by code to identify patterns:
  • High UNAUTHORISED rates may indicate token refresh issues
  • High RATE_LIMIT_EXCEEDED rates suggest too frequent requests
  • High DATABASE_ERROR rates indicate infrastructure issues

Error Logging Behaviour

The API logs errors at different severity levels:

Client Errors (4xx)

Logged at DEBUG level as these are expected client mistakes:
  • Missing required fields
  • Invalid input format
  • Authentication failures

Server Errors (5xx)

Logged at ERROR level as these indicate server-side issues:
  • Database connection failures
  • Unexpected exceptions
  • Service unavailability
All error logs include the request_id for tracing requests through the system.

Build docs developers (and LLMs) love