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

# Handling Errors

> Error codes, rate limits, and common troubleshooting steps for the Sixtyfour API.

## Error Response Format

All Sixtyfour API errors return a JSON response with a consistent structure:

```json theme={null}
{
  "error": "Error Type",
  "message": "Detailed error message"
}
```

Some endpoints may use an alternative format:

```json theme={null}
{
  "detail": "Error description"
}
```

Workflows and other endpoints may return 422 validation errors with a structured `detail` array:

```json theme={null}
{
  "detail": [
    {
      "loc": ["body", "workflow_name"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}
```

## HTTP Status Codes

The API uses standard HTTP status codes to indicate success or failure.

| Status Code | Meaning | Description |
| - | - | - |
| 200 | OK | Request succeeded |
| 400 | Bad Request | Invalid request body, missing required fields, or malformed data |
| 401 | Unauthorized | Missing or invalid API key |
| 402 | Payment Required | Insufficient balance to cover the estimated cost of a bulk job |
| 403 | Forbidden | Feature not enabled for your organization (e.g., high or xhigh tier enrichment) |
| 404 | Not Found | Resource not found (e.g., workflow or run ID, or an unknown profile photo key) |
| 409 | Conflict | The resource is not in a state that allows the request (e.g., triggering a cancelled monitor), or an identical request is still being processed |
| 422 | Validation Error | Invalid request parameters; see `detail` array for field-level errors |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error - retry after a brief wait |
| 502 | Bad Gateway | An upstream source failed (e.g., a profile photo could not be fetched) - retry after a brief wait |
| 503 | Service Unavailable | Temporarily unavailable or at capacity - retry after a brief wait, or after the `Retry-After` header when present |

## Common Error Types

### 400 Bad Request

**Causes:**

* Missing required fields in request body
* Invalid field types or formats
* Malformed JSON payload
* Empty or invalid lead/company data
* Sending `webhook_payload` to `/workflows/run` for a workflow whose source block is not `webhook`
* Sending `webhook_payload` with JWT (dashboard session) auth instead of an API key
* Triggering a `read_csv` workflow without a valid `specs_override.resource_handle_id` from `/storage/csv/upload`, or with a `handle_id` that has expired or belongs to a different organization
* `webhook_payload` is missing required columns from the `webhook` block's `input_schema`, or is malformed JSON
* Invalid search exclusions: sending `exclude_public_ids` in company mode (people-only) or alongside `exclude_entity_ids`, using a saved exclusion list whose entity type doesn't match the search mode or that is not yet `ready`, or sending exclusions on a cursor request — see [Search Exclusions](/api-reference/search/search-exclusions)
* Invalid monitor definitions: a `frequency` outside `1h`–`30d`, a `tier` other than `low`, `medium`, or `high`, a `subject_type` other than `company` or `lead`, an empty `struct`, a column used as both a key column and a watched field, a row with no value in any key column, two rows with the same key values, or a non-public `webhook_url` — see [Monitor Endpoints](/api-reference/monitors/monitors-endpoints)
* Invalid monitor uploads: a file that is not `.csv`, `.json`, `.jsonl`, or `.ndjson`, is larger than 100 MB, has no rows or more than 100,000 rows, or cannot be parsed; a `config` that is not valid JSON, contains an unknown field, has an empty or invalid `webhook_event_types` list, or names a `key_columns` entry missing from the file— see [Create monitor from a file](/api-reference/monitors/monitors-endpoints#create-monitor-from-a-file)
* A `cursor` for `GET /monitors/{monitor_id}/rows` that did not come from a previous `next_cursor` — see [List rows](/api-reference/monitors/monitors-endpoints#list-rows)

**Examples:**

```json theme={null}
{
  "error": "Bad Request",
  "message": "Invalid company data"
}
```

```json theme={null}
{
  "error": "Bad Request",
  "message": "Invalid lead data"
}
```

```json theme={null}
{
  "detail": "Lead data is required"
}
```

```json theme={null}
{
  "error": "Bad Request",
  "message": "Missing required field: qualification_criteria"
}
```

```json theme={null}
{
  "detail": "Rows 0 and 3 have the same identity values (Acme Robotics, acmerobotics.com). Add a column that tells them apart, or remove the duplicate."
}
```

**How to fix:**

* Verify all required fields are included in your request
* Check that field types match the API specification
* Ensure JSON is properly formatted
* Validate input data before making the request
* For workflow runs, match the request body to the source block: `webhook_payload` for `webhook` workflows ([Incoming Webhooks](/api-reference/webhooks/incoming)) or `specs_override.resource_handle_id` for `read_csv` workflows ([Workflow Execution](/api-reference/workflows/workflows-execution)). `webhook_payload` requires API key or OAuth auth — JWT (dashboard session) is rejected.

### 401 Unauthorized

**Causes:**

* Missing `x-api-key` header
* Invalid or expired API key
* API key not properly formatted

**Example:**

```json theme={null}
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}
```

**How to fix:**

* Verify your API key is correct
* Ensure the `x-api-key` header is included in every request
* Check that your API key hasn't been revoked or expired
* Get a new API key from the [dashboard](https://app.sixtyfour.ai)

### 402 Payment Required

**Causes:**

* Your balance doesn't cover the estimated cost of a [bulk intelligence](/api-reference/endpoint/bulk-intelligence) job (`rows × per-row tier price`)

**How to fix:**

* Add credits in the [dashboard](https://app.sixtyfour.ai) before resubmitting
* Reduce the row count or use a cheaper tier to lower the estimated cost

Nothing is charged when a request returns 402.

### 403 Forbidden

**Causes:**

* Requesting a feature that is not enabled for your organization (e.g., `tier: "micro"`, `tier: "high"`, or `tier: "xhigh"` enrichment)
* Calling any `/monitors` endpoint when Monitors are not enabled for your organization
* Creating or updating a monitor with the `5m` frequency or `micro` tier when testing monitors are not enabled for your organization

**Examples:**

```json theme={null}
{
  "detail": "High tier company enrichment is not enabled for this org. Contact sales to request access."
}
```

```json theme={null}
{
  "detail": "X-High tier lead enrichment is not enabled for this org. Contact sales to request access."
}
```

```json theme={null}
{
  "detail": "Monitors are not enabled for your organization."
}
```

**How to fix:**

* Verify your organization has access to the requested feature
* Contact sales to request access to restricted tiers
* Use a lower tier (`"low"`, `"medium"`, or `"high"` if available) if xhigh tier access is not available

### 409 Conflict (Monitors)

**Causes:**

* Triggering a monitor that is cancelled or paused
* Updating a cancelled monitor or switching one of its rows on or off
* Reusing a monitor idempotency key with different creation settings or file contents, or with an older explicit key whose original request cannot be verified
* Triggering a monitor, or changing its `frequency` or `is_active`, while its `status` is `starting` or `failed`, before every row from an uploaded file is added
* Sending a create request while an identical one, with the same idempotency key, is still being processed

**Examples:**

```json theme={null}
{
  "detail": "This monitor is not active."
}
```

```json theme={null}
{
  "detail": "This request is already being processed. Retry shortly."
}
```

**How to fix:**

* For a paused monitor, resume it with `POST /monitors/{monitor_id}/update` and `"is_active": true`, then trigger it
* For a monitor whose `status` is `starting`, wait until it is `active`. For one whose `status` is `failed`, send the same upload request again, with the same file and settings, to finish it
* A cancelled monitor cannot be resumed or changed. Create a new monitor to start checks again
* For an idempotency conflict, retry with the original creation payload. Use a new key for a new monitor, or when an older explicit key cannot be verified
* If the request is still being processed, retry after a few seconds with the same payload and key; it returns what the first attempt created

### 502 Bad Gateway (Monitor Cancellation)

If cancellation is saved but stopping the schedule fails, the API returns:

```json theme={null}
{
  "detail": "Monitor is cancelled, but its schedule could not be paused. Retry cancellation to finish cleanup."
}
```

The monitor remains cancelled and no further row checks run. Retry `POST /monitors/{monitor_id}/cancel` to finish pausing the schedule. Repeating cancellation is safe.

### 404 Not Found (Workflows)

**Causes:**

* Workflow ID does not exist or was deleted
* Run/job ID does not exist or is invalid
* Resource does not belong to your organization
* Monitor or row ID does not exist, or the monitor belongs to another team

**Example:**

```json theme={null}
{
  "detail": "Workflow not found"
}
```

**How to fix:**

* Verify the workflow ID using `GET /workflows`
* Verify the job\_id from your run response
* Ensure you're accessing resources created by your organization

### 422 Validation Error (Monitors)

`POST /monitors/{monitor_id}/update` rejects any request containing `struct`, including `null`, an empty object, or the existing definition. The entire request is rejected before other fields are applied. Create a new monitor to change its watched fields.

For JSON monitor creation (`POST /monitors`) and updates (`POST /monitors/{monitor_id}/update`), `webhook_event_types` must be a nonempty list containing only `monitor.field.changed`, `monitor.execution.completed`, `monitor.execution.failed`, or `monitor.run.completed`. Empty lists, unknown names, and invalid field types return `422` with a field-level `detail` array. Send `null` on update to restore the default subscription, or omit the field to leave it unchanged.

### 422 Validation Error (Workflows and Other Monitor Requests)

**Causes:**

* Invalid workflow definition (empty blocks, incompatible block types)
* Missing required fields in create/update requests
* Invalid block or edge configuration
* Unknown fields in monitor create, update, row-toggle, source, or history-export JSON requests, such as `frequncy` instead of `frequency`
* Toggling a monitor row without the required JSON body `{"is_active": false}` or `{"is_active": true}`; the query parameter alone is not accepted

**Example:**

```json theme={null}
{
  "detail": [
    {
      "loc": ["body", "workflow_definition", "blocks"],
      "msg": "blocks cannot be empty",
      "type": "value_error"
    }
  ]
}
```

**How to fix:**

* Ensure workflow has at least one block and valid edges
* Check block compatibility (e.g., webhook → company\_enrichment)
* Use the workflow editor's "Workflow API Reference" for block specs

### 429 Rate Limit Exceeded

**Causes:**

* Exceeded the rate limit of 500 requests per minute
* Exceeded 120 requests per minute for your organization on `POST /verify-email`

**Example:**

```json theme={null}
{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded"
}
```

**How to fix:**

* Implement exponential backoff and retry logic
* Wait the number of seconds in the `Retry-After` header when present, otherwise 60 seconds, before retrying
* Spread requests over time to stay under the limit
* Use async endpoints for bulk operations
* Contact support if you need a higher rate limit

### 500 Internal Server Error

**Causes:**

* Temporary server issue
* Unexpected error during processing
* Service degradation

**Example:**

```json theme={null}
{
  "error": "Internal Server Error",
  "message": "An unexpected error occurred"
}
```

**How to fix:**

* Wait a few seconds and retry the request
* Implement retry logic with exponential backoff
* If the error persists, contact support at [support@sixtyfour.ai](mailto:support@sixtyfour.ai)

### 503 Service Unavailable (Verify Email)

When the email check returns no verdict, `POST /verify-email` returns:

```json theme={null}
{
  "detail": "Email verification is temporarily unavailable. Retry shortly."
}
```

The request is not charged. Retry it after a brief wait.

## Rate Limits

The Sixtyfour API enforces the following rate limits:

* **500 requests per minute** per API key
* **5 concurrent deep searches** per organization
* **120 requests per minute** per organization on `POST /verify-email`

Rate limit information may be included in response headers (if available):

* `X-RateLimit-Limit`: Maximum requests allowed per minute
* `X-RateLimit-Remaining`: Remaining requests in current window
* `X-RateLimit-Reset`: Unix timestamp when the limit resets

### Best Practices for Rate Limiting

1. **Implement Retry Logic**

```python theme={null}
import requests
import time

def make_request_with_retry(url, headers, data, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(url, headers=headers, json=data)

            if response.status_code == 429:
                wait_time = 2 ** attempt  # Exponential backoff
                print(f"Rate limit exceeded. Waiting {wait_time} seconds...")
                time.sleep(wait_time)
                continue

            response.raise_for_status()
            return response.json()

        except requests.exceptions.RequestException as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)

    raise Exception("Max retries exceeded")
```

2. **Use Async Endpoints or Workflows for Bulk Operations**

For processing multiple items, use async endpoints (`/company-intelligence-async`, `/people-intelligence-async`) or the [Workflows API](/api-reference/workflows/workflows-overview) instead of making many synchronous calls.

3. **Implement Request Queuing**

Queue requests and process them at a controlled rate to stay under the limit.

## Timeout Issues

### Long-Running Requests

Some endpoints perform deep research and can take several minutes:

* **People Intelligence**: P95 runtime \~5 minutes, up to 10 minutes
* **Company Intelligence**: Several minutes depending on research depth
* **QA Agent**: Varies based on criteria complexity

**Solutions:**

1. **Set Appropriate Timeouts**

<CodeGroup>
  ```python Python theme={null}
  import requests

  # For sync endpoints, set timeout to at least 15 minutes (900 seconds)
  response = requests.post(
      "https://api.sixtyfour.ai/people-intelligence",
      headers=headers,
      json=data,
      timeout=900  # 15 minutes
  )
  response.raise_for_status()
  ```

  ```javascript JavaScript theme={null}
  // For sync endpoints, set timeout to at least 15 minutes (900000 ms)
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 900000); // 15 minutes

  try {
    const response = await fetch("https://api.sixtyfour.ai/people-intelligence", {
      method: "POST",
      headers: headers,
      body: JSON.stringify(data),
      signal: controller.signal
    });
    clearTimeout(timeoutId);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const result = await response.json();
  } catch (error) {
    clearTimeout(timeoutId);
    if (error.name === 'AbortError') {
      console.error('Request timed out after 15 minutes');
    } else {
      throw error;
    }
  }
  ```
</CodeGroup>

2. **Use Async Endpoints**

<CodeGroup>
  ```python Python theme={null}
  import requests
  import time

  # Start async job
  response = requests.post(
      "https://api.sixtyfour.ai/people-intelligence-async",
      headers=headers,
      json=data
  )
  response.raise_for_status()
  task_id = response.json()["task_id"]

  # Poll for results
  while True:
      status_response = requests.get(
          f"https://api.sixtyfour.ai/job-status/{task_id}",
          headers=headers
      )
      status_response.raise_for_status()
      status = status_response.json()

      if status["status"] == "completed":
          results = status["result"]
          break
      elif status["status"] in ("failed", "cancelled", "terminated", "timed_out"):
          print(f"Job {status['status']}: {status.get('error')}")
          break

      time.sleep(10)
  ```

  ```javascript JavaScript theme={null}
  // Start async job
  const response = await fetch("https://api.sixtyfour.ai/people-intelligence-async", {
    method: "POST",
    headers: headers,
    body: JSON.stringify(data)
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const taskInfo = await response.json();
  const taskId = taskInfo.task_id;

  // Poll for results
  while (true) {
    const statusResponse = await fetch(
      `https://api.sixtyfour.ai/job-status/${taskId}`,
      { headers: headers }
    );

    if (!statusResponse.ok) {
      throw new Error(`HTTP error! status: ${statusResponse.status}`);
    }

    const status = await statusResponse.json();

    if (status.status === "completed") {
      const results = status.result;
      break;
    } else if (["failed", "cancelled", "terminated", "timed_out"].includes(status.status)) {
      console.error(`Job ${status.status}: ${status.error || "Unknown error"}`);
      break;
    }

    // Wait 10 seconds before polling again
    await new Promise(resolve => setTimeout(resolve, 10000));
  }
  ```
</CodeGroup>

3. **Use Webhooks**

Configure webhooks to receive notifications when async jobs complete. See [Outgoing Webhooks](/api-reference/webhooks/outgoing).

## Common Troubleshooting Scenarios

### Issue: "Invalid API key" error

**Check:**

* Is the `x-api-key` header included?
* Is the API key copied correctly (no extra spaces)?
* Has the API key been revoked or expired?

**Solution:** Get your API key from the [dashboard](https://app.sixtyfour.ai) and verify it's correctly included in the header.

***

### Issue: Request times out

**Check:**

* Are you using a sync endpoint for long-running operations?
* Is your HTTP client timeout set appropriately?

**Solution:** Use async endpoints or increase client timeout to at least 15 minutes (900 seconds).

***

### Issue: Empty or incomplete results

**Check:**

* Did you provide enough input data for the enrichment?
* Is the `struct` field properly defined with clear descriptions?
* Are you requesting data that may not be publicly available?

**Solution:**

* Provide as much input data as possible (name, company, LinkedIn, etc.)
* Write clear, detailed descriptions in the `struct` field
* Check the `confidence_score` in the response to gauge data quality

***

### Issue: Rate limit exceeded frequently

**Check:**

* Are you making more than 500 requests per minute?
* Are you implementing retry logic properly?

**Solution:**

* Use async endpoints for bulk operations
* Implement request queuing to control the rate
* Add delays between requests
* Contact support if you need a higher limit

***

### Issue: "Bad Request" with valid data

**Check:**

* Is the JSON properly formatted?
* Are all required fields included?
* Are field types correct (object vs string, etc.)?

**Solution:** Validate your JSON payload and compare against the endpoint documentation.

***

### Issue: Workflow run stuck or not progressing

**Check:**

* Are you polling `GET /workflows/runs/{run_id}/live_status`?
* Is the `overall_status` still `queued` or `running`?
* Has the workflow been running for an unusually long time?

**Solution:**

* Poll every 5-10 seconds; workflow runs can take several minutes
* Use `overall_progress_percentage` and `blocks` to see per-block progress
* To stop a run: `POST /workflows/cancel?job_id={job_id}`
* If a run appears stuck, check `error_message` in block status; consider cancelling and retrying

***

### Issue: Webhook signature verification fails or deliveries stop

**Check:**

* Is your verifier using the **raw request body bytes**, not a re-serialized JSON parse?
* During rotation, does it iterate every `v1=` segment (not only the last)?
* Is your server clock within 5 minutes of UTC?
* Are you using the plaintext secret (`sk_whsec_<64 hex>`), not the masked preview shown in the dashboard?

**Solution:**

* Log the raw body, the `Sixtyfour-Signature` header, and the HMAC your server computes; compare against what we sent.
* See [Signing Secrets & Verification](/api-reference/webhooks/signing-secrets) for the verification algorithm and reference code.
* If deliveries stop entirely, we may be refusing to deliver unsigned when signing is configured (fail-closed by design). Results remain available via `/job-status/{task_id}`.

### Verify Phone column mappings

Rows with a phone but no value in the configured `name_column` skip verification without failing the batch. They return `Missing Name` in `phone_warnings` and `MissingRequiredInput` details in `phone_errors`.

The name mapping must match the input column. For example, data containing `fullName` requires `name_column: "fullName"`. See [Configure Verify Phone](/guides/building-workflows#configure-verify-phone) to update a saved mapping.

A missing phone column fails the block; a blank phone value skips the row.

## Getting Help

If you're experiencing issues not covered in this guide:

1. Check the [API Reference](/api-quick-start) for endpoint-specific requirements
2. Review the [starter notebooks](/starter-notebooks/company-intelligence-tutorial) for working examples
3. Contact support at [support@sixtyfour.ai](mailto:support@sixtyfour.ai)
4. Include the following in your support request:
   * Request/response details (remove sensitive data)
   * Error message
   * Endpoint being called
   * Approximate timestamp of the error


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.