> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firstquadrant.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Error handling

> Understanding and handling errors in the FirstQuadrant API

The FirstQuadrant API uses conventional HTTP response codes to indicate the success or failure of an API request. This guide explains our error format and how to handle common errors.

## HTTP status codes

| Status Code | Description                                                   |
| ----------- | ------------------------------------------------------------- |
| `200`       | Success - The request completed successfully                  |
| `201`       | Created - A new resource was created successfully             |
| `204`       | No Content - The request succeeded with no response body      |
| `400`       | Bad Request - The request was invalid or malformed            |
| `401`       | Unauthorized - Authentication failed or missing               |
| `403`       | Forbidden - Valid authentication but insufficient permissions |
| `404`       | Not Found - The requested resource doesn't exist              |
| `409`       | Conflict - The request conflicts with existing data           |
| `422`       | Unprocessable Entity - Validation errors                      |
| `429`       | Too Many Requests - Rate limit exceeded                       |
| `500`       | Internal Server Error - Something went wrong on our end       |

## Error response format

All errors follow a consistent JSON structure:

```json theme={null}
{
  "code": "validation_error",
  "status": 422,
  "message": "Validation failed",
  "description": "The request body contains invalid data.",
  "details": [
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ]
}
```

### Error response fields

| Field         | Type   | Description                                      |
| ------------- | ------ | ------------------------------------------------ |
| `code`        | string | Machine-readable error code                      |
| `status`      | number | HTTP status code                                 |
| `message`     | string | Brief human-readable message                     |
| `description` | string | Detailed explanation of the error                |
| `details`     | array  | Additional error details (for validation errors) |

## Common error codes

### Authentication errors

| Code                       | Status | Description                                        |
| -------------------------- | ------ | -------------------------------------------------- |
| `missing_authorization`    | 401    | No authentication credentials provided             |
| `invalid_token`            | 401    | The provided token is invalid or expired           |
| `insufficient_permissions` | 403    | Valid credentials but lacking required permissions |
| `missing_scopes`           | 403    | API key doesn't have required scopes               |

### Validation errors

| Code                     | Status | Description                       |
| ------------------------ | ------ | --------------------------------- |
| `validation_error`       | 422    | Request body validation failed    |
| `invalid_parameters`     | 400    | Query parameters are invalid      |
| `missing_required_field` | 422    | A required field is missing       |
| `invalid_field_value`    | 422    | A field contains an invalid value |

### Resource errors

| Code              | Status | Description                                        |
| ----------------- | ------ | -------------------------------------------------- |
| `not_found`       | 404    | The requested resource doesn't exist               |
| `already_exists`  | 409    | A resource with the same identifier already exists |
| `resource_locked` | 423    | The resource is locked and cannot be modified      |

### Rate limiting

| Code           | Status | Description                         |
| -------------- | ------ | ----------------------------------- |
| `rate_limited` | 429    | Too many requests in a short period |

## Error handling examples

<CodeGroup>
  ```javascript JavaScript theme={null}
  try {
    const response = await fetch("https://api.us.firstquadrant.ai/v5/contacts", {
      method: "POST",
      headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "FirstQuadrant-Organization-ID": "org_YOUR_ORG_ID",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        email: "invalid-email",
        firstName: "John",
      }),
    });

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

      switch (error.code) {
        case "validation_error":
          console.error("Validation failed:", error.details);
          break;
        case "rate_limited":
          console.error("Rate limit hit, retry after delay");
          break;
        case "missing_authorization":
          console.error("Authentication required");
          break;
        default:
          console.error("API error:", error.message);
      }
    }
  } catch (err) {
    console.error("Network error:", err);
  }
  ```

  ```python Python theme={null}
  import requests
  from time import sleep

  def make_api_request(url, data=None, retry_count=0):
      try:
          response = requests.post(
              url,
              json=data,
              headers={
                  'Authorization': 'Bearer YOUR_API_KEY',
                  'FirstQuadrant-Organization-ID': 'org_YOUR_ORG_ID'
              }
          )

          if response.status_code == 429 and retry_count < 3:
              # Rate limited, retry with exponential backoff
              sleep(2 ** retry_count)
              return make_api_request(url, data, retry_count + 1)

          response.raise_for_status()
          return response.json()

      except requests.exceptions.HTTPError as err:
          error_data = err.response.json()

          if error_data['code'] == 'validation_error':
              print(f"Validation errors: {error_data['details']}")
          else:
              print(f"API error: {error_data['message']}")

          raise
  ```

  ```typescript TypeScript theme={null}
  interface ApiError {
    code: string;
    status: number;
    message: string;
    description: string;
    details?: Array<{
      field: string;
      message: string;
    }>;
  }

  class FirstQuadrantError extends Error {
    constructor(
      public code: string,
      public status: number,
      message: string,
      public details?: any[],
    ) {
      super(message);
    }
  }

  async function apiRequest<T>(endpoint: string, options?: RequestInit): Promise<T> {
    const response = await fetch(`https://api.us.firstquadrant.ai/v5${endpoint}`, {
      ...options,
      headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "FirstQuadrant-Organization-ID": "org_YOUR_ORG_ID",
        "Content-Type": "application/json",
        ...options?.headers,
      },
    });

    if (!response.ok) {
      const error: ApiError = await response.json();
      throw new FirstQuadrantError(error.code, error.status, error.message, error.details);
    }

    return response.json();
  }

  // Usage with error handling
  try {
    const contact = await apiRequest("/contacts", {
      method: "POST",
      body: JSON.stringify({ email: "test@example.com" }),
    });
  } catch (error) {
    if (error instanceof FirstQuadrantError) {
      if (error.code === "validation_error") {
        // Handle validation errors
        error.details?.forEach((detail) => {
          console.error(`${detail.field}: ${detail.message}`);
        });
      }
    }
  }
  ```
</CodeGroup>

## Validation error details

When a validation error occurs, the `details` array provides specific information about each field that failed validation:

```json theme={null}
{
  "code": "validation_error",
  "status": 422,
  "message": "Validation failed",
  "description": "The request body contains invalid data.",
  "details": [
    {
      "field": "email",
      "message": "Invalid email format"
    },
    {
      "field": "phone",
      "message": "Phone number must include country code"
    },
    {
      "field": "customProperties.industry",
      "message": "Industry must be one of: technology, finance, healthcare"
    }
  ]
}
```

## Best practices

1. **Always check the response status** before attempting to parse the response body
2. **Handle rate limiting gracefully** by implementing exponential backoff
3. **Log error details** including the `X-Request-Id` header for debugging
4. **Parse validation errors** to provide user-friendly feedback
5. **Implement retry logic** for transient errors (5xx status codes)
6. **Use the error code** for programmatic error handling rather than parsing messages

## Debugging

When reporting issues, include:

* The `X-Request-Id` header from the response
* The full error response body
* The request method, URL, and headers (excluding sensitive data)
* The request body (if applicable)

This information helps our support team quickly identify and resolve issues.
