Error Handling

The ezylegal API uses conventional HTTP response codes to indicate the success or failure of an API request. This guide explains how to handle errors effectively.

Error Response Format

All errors return a consistent JSON structure:

{
  "error": {
    "code": "invalid_request",
    "message": "The form_type field is required",
    "details": {
      "field": "form_type",
      "reason": "required"
    }
  }
}

Error Object

| Field | Type | Description | |-------|------|-------------| | code | string | Machine-readable error code | | message | string | Human-readable error description | | details | object | Additional context (optional) |


HTTP Status Codes

2xx - Success

| Code | Description | |------|-------------| | 200 OK | Request succeeded | | 201 Created | Resource created successfully | | 202 Accepted | Request accepted, processing async | | 204 No Content | Request succeeded, no response body |

4xx - Client Errors

| Code | Description | |------|-------------| | 400 Bad Request | Invalid request syntax or parameters | | 401 Unauthorized | Missing or invalid authentication | | 403 Forbidden | Valid auth but insufficient permissions | | 404 Not Found | Resource doesn't exist | | 409 Conflict | Request conflicts with current state | | 422 Unprocessable Entity | Request understood but invalid | | 429 Too Many Requests | Rate limit exceeded |

5xx - Server Errors

| Code | Description | |------|-------------| | 500 Internal Server Error | Unexpected server error | | 502 Bad Gateway | Upstream service error | | 503 Service Unavailable | Service temporarily unavailable | | 504 Gateway Timeout | Upstream service timeout |


Common Error Codes

Authentication Errors

unauthorized

{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
}

Cause: No API key provided or invalid format. Solution: Include Authorization: Bearer YOUR_API_KEY header.

invalid_api_key

{
  "error": {
    "code": "invalid_api_key",
    "message": "The provided API key is invalid or has been revoked"
  }
}

Cause: API key doesn't exist or was deleted. Solution: Check your API key or generate a new one.

Validation Errors

invalid_request

{
  "error": {
    "code": "invalid_request",
    "message": "Invalid request parameters",
    "details": {
      "errors": [
        {"field": "form_type", "reason": "required"},
        {"field": "customer_email", "reason": "invalid_format"}
      ]
    }
  }
}

Cause: One or more request parameters are invalid. Solution: Check the details.errors array for specific issues.

invalid_json

{
  "error": {
    "code": "invalid_json",
    "message": "The request body is not valid JSON"
  }
}

Cause: Request body contains malformed JSON. Solution: Validate your JSON before sending.

Resource Errors

session_not_found

{
  "error": {
    "code": "session_not_found",
    "message": "Session not found"
  }
}

Cause: The session ID doesn't exist. Solution: Check the session ID is correct.

session_expired

{
  "error": {
    "code": "session_expired",
    "message": "This session has expired"
  }
}

Cause: The session passed its expiration date. Solution: Create a new session if needed.

session_completed

{
  "error": {
    "code": "session_completed",
    "message": "This operation is not allowed on completed sessions"
  }
}

Cause: Attempted to modify a completed session. Solution: Completed sessions are immutable.

Rate Limiting

rate_limit_exceeded

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Retry after 30 seconds"
  }
}

Cause: Too many requests in a short time. Solution: Wait and retry with exponential backoff.

Headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705320030
Retry-After: 30

Error Handling Best Practices

1. Check HTTP Status First

const response = await fetch('/v1/sessions', options);

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

return response.json();

2. Handle Specific Error Codes

try {
  const session = await createSession(data);
} catch (error) {
  switch (error.code) {
    case 'invalid_request':
      // Show validation errors to user
      showValidationErrors(error.details.errors);
      break;
    case 'rate_limit_exceeded':
      // Retry after delay
      await delay(error.retryAfter * 1000);
      return createSession(data);
    case 'unauthorized':
      // Refresh credentials
      await refreshApiKey();
      return createSession(data);
    default:
      // Log and show generic error
      console.error('Unexpected error:', error);
      showGenericError();
  }
}

3. Implement Retry Logic

For transient errors (5xx, rate limits), 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') || 30;
        await delay(retryAfter * 1000);
        continue;
      }

      if (response.status >= 500) {
        await delay(Math.pow(2, i) * 1000);
        continue;
      }

      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await delay(Math.pow(2, i) * 1000);
    }
  }
}

4. Log Errors Appropriately

Include relevant context for debugging:

console.error({
  error: error.code,
  message: error.message,
  requestId: response.headers.get('X-Request-ID'),
  timestamp: new Date().toISOString(),
  endpoint: url,
  method: options.method,
});

Getting Help

If you encounter persistent errors:

  1. Check our status page for outages
  2. Include the X-Request-ID header when contacting support
  3. Email [email protected] with error details