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

# Errors

> HTTP status codes, error response format, retries, and client handling for the Verification API.

# Errors

The Verification API uses conventional HTTP status codes and JSON error bodies.

Related: [SLA and escalation](/guides/sla-and-escalation) · [Troubleshooting](/troubleshooting)

## HTTP status codes

Public integration endpoints most often return these codes:

| Status Code | Description                                                                                                    |
| ----------- | -------------------------------------------------------------------------------------------------------------- |
| `200`       | Success — request completed successfully                                                                       |
| `201`       | Created — resource created successfully                                                                        |
| `400`       | Bad Request — invalid parameters or missing required fields                                                    |
| `401`       | Unauthorized — invalid or missing authentication                                                               |
| `404`       | Not Found — resource doesn't exist (some read endpoints return `200` with an `error` body instead — see below) |
| `500`       | Internal Server Error — something went wrong on our end                                                        |

`403` (Forbidden) and `409` (Conflict) can appear on internal admin tooling. They are uncommon on the documented consumer routes in this site; treat them as non-retryable if you see them.

## Error response format

```json theme={null}
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request"
}
```

For validation errors with multiple issues:

```json theme={null}
{
  "statusCode": 400,
  "message": ["proposedSalary must be a number", "applicant.ssn should not be empty"],
  "error": "Bad Request"
}
```

## Common error scenarios

### Authentication errors (401)

**Missing Authorization header:**

```json theme={null}
{
  "statusCode": 401,
  "message": "Unauthorized"
}
```

All authentication failures — missing header, malformed token, expired token, invalid signature — collapse to this same generic `401 Unauthorized` body. There is no separate "invalid or expired token" message.

### Validation errors (400)

**Missing required fields:**

```json theme={null}
{
  "statusCode": 400,
  "message": ["applicant.firstName should not be empty", "applicant.ssn should not be empty", "entityName should not be empty"],
  "error": "Bad Request"
}
```

**Invalid date format:**

```json theme={null}
{
  "statusCode": 400,
  "message": ["history.employment.0.startDate must be a valid date in YYYY-MM-DD format"],
  "error": "Bad Request"
}
```

**Unsupported search type:**

Only `EMPLOYMENT` and `EDUCATION` are accepted. Requesting `CRIMINAL`, `REFERENCE`, or any other value returns `searchType must be EMPLOYMENT or EDUCATION` for the offending entry — a common validation error worth checking for before you retry.

### Order or search not found

[Get order](/api-reference/endpoints/get-order) and [Get specific search](/api-reference/endpoints/get-specific-search) return HTTP `200` with an `error` field in the body when a resource is not found. Check for the `error` field in addition to the status code.

**Order not found:**

```json theme={null}
{
  "error": "Order not found",
  "orderId": "123e4567-e89b-12d3-a456-426614174000"
}
```

**Search not found:**

```json theme={null}
{
  "error": "Search not found",
  "orderId": "123e4567-e89b-12d3-a456-426614174000",
  "searchId": "456e7890-e89b-12d3-a456-426614174001"
}
```

## Client handling

### Check status codes

```javascript theme={null}
const response = await fetch('https://sandbox.theary.ai/background-check/v1/orders', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_JWT_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(orderData),
})

if (!response.ok) {
  const errorData = await response.json()
  console.error('API Error:', errorData)

  switch (response.status) {
    case 400:
      console.error('Validation Error:', errorData.message)
      break
    case 401:
      console.error('Authentication Error - Check your token')
      break
    case 404:
      console.error('Resource not found')
      break
    default:
      console.error('Unexpected error:', response.status)
  }

  throw new Error(`API Error: ${response.status}`)
}

const data = await response.json()
```

### Retry logic

Retry transient errors (`5xx`, network issues) with exponential backoff. Do **not** retry `4xx` — fix the request instead.

```javascript theme={null}
async function createOrderWithRetry(orderData, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    let response
    try {
      response = await fetch('https://sandbox.theary.ai/background-check/v1/orders', {
        method: 'POST',
        headers: {
          Authorization: 'Bearer YOUR_JWT_TOKEN',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(orderData),
      })
    } catch (error) {
      // Network failure — retry with backoff
      if (attempt === maxRetries) throw error
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000))
      continue
    }

    if (response.ok) {
      return await response.json()
    }

    // Do not retry client errors — fix the request or token instead
    if (response.status >= 400 && response.status < 500) {
      throw new Error(`Client Error: ${response.status}`)
    }

    if (attempt === maxRetries) {
      throw new Error(`Server Error after ${maxRetries} attempts: ${response.status}`)
    }

    await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000))
  }
}
```

Order creation is **not idempotent**. If a create call fails without a clear response, reconcile by `externalSearchId` before retrying. See [Quickstart — Production readiness](/quickstart#production-readiness).
