> For the complete documentation index, see [llms.txt](https://docs.heron-intelligence.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.heron-intelligence.com/documentation/error-handling.md).

# Error Handling

Comprehensive guide to handling errors and troubleshooting issues with the Heron Intelligence Data Product API.

## HTTP Status Codes

### Success Codes

| Code  | Status     | Returned by                                                                                   |
| ----- | ---------- | --------------------------------------------------------------------------------------------- |
| `200` | OK         | All `GET` endpoints, and `PATCH /api/v1/watchlist/{watchlist_id}`                             |
| `201` | Created    | `POST /api/v1/operations/research-request`, `POST /api/v1/watchlist`, `POST /api/v1/webhooks` |
| `204` | No Content | `DELETE /api/v1/webhooks/{subscription_id}` — empty body on success                           |

### Client Error Codes

| Code  | Status               | Description                              | Common Causes                                                                                                                                                                                                                       |
| ----- | -------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Bad Request          | Malformed request                        | Invalid JSON, missing headers                                                                                                                                                                                                       |
| `401` | Unauthorized         | Authentication failed                    | Invalid/missing API key                                                                                                                                                                                                             |
| `403` | Forbidden            | Access denied                            | Insufficient permissions                                                                                                                                                                                                            |
| `404` | Not Found            | Resource not found                       | Invalid endpoint; a `research_id` or `subscription_id` that does not exist **or belongs to another client**                                                                                                                         |
| `409` | Conflict             | The request names more than one resource | `company_ticker` on `GET /api/v1/evasion/analyses` that more than one company carries — the body lists the candidates; repeat with `company_id`. See [Evasion](/api-reference/api-reference/evasion.md#a-ticker-is-not-an-identity) |
| `422` | Unprocessable Entity | Validation error                         | Malformed UUID, out-of-range `per_page`, value outside an enum, missing template variables                                                                                                                                          |
| `429` | Too Many Requests    | Rate limit exceeded                      | Too frequent requests                                                                                                                                                                                                               |

### Server Error Codes

| Code  | Status                | Description   | Action                    |
| ----- | --------------------- | ------------- | ------------------------- |
| `500` | Internal Server Error | Server error  | Retry after delay         |
| `502` | Bad Gateway           | Gateway error | Check service status      |
| `503` | Service Unavailable   | Service down  | Wait and retry            |
| `504` | Gateway Timeout       | Timeout error | Retry with longer timeout |

## The `422` validation body

Validation failures return a `detail` array with one entry per offending field. `loc` is the path to the field — its first element is the location (`query`, `body`, `path`), the rest name the field.

```json
{
  "detail": [
    {
      "loc": ["query", "per_page"],
      "msg": "Input should be less than or equal to 100",
      "type": "less_than_equal"
    }
  ]
}
```

Read `loc` rather than string-matching on `msg` — the wording is not a stable contract.

### Research request templates

`POST /api/v1/operations/research-request` with a `template` and missing variable fields returns `422` with a `missing_fields` array naming the gaps. See [Research Request](/api-reference/api-reference/research-request.md) for which fields each template requires.

## `404` means "not visible to you"

`404` does not distinguish "does not exist" from "exists but belongs to someone else". Cross-scope reads — another firm's project, or another client's webhook subscription — are deliberately returned as `404` rather than `403`, so that ids cannot be probed. When you get a `404` on an id you believe is valid, check the `scope` parameter and the API key before assuming the record is gone.

## An empty result is not an error

A filtered request that matches nothing returns `200` with an empty `data` array and `total_items: 0`. Two cases look identical:

* **No coverage** — no interview matches the filters.
* **Not entitled** — you filtered by a `data_source_provider_ids` value your API key cannot read.

{% hint style="warning" %}
Never report a provider-filtered empty result as an absence of research. Re-run the request without `data_source_provider_ids`; if results appear, the gap is entitlement, not coverage. Check [`GET /api/v1/data-sources`](/api-reference/api-reference/data-sources.md) for what your key can read, and see [Data Providers](/documentation/data-providers.md#access-depends-on-your-subscription).
{% endhint %}

## Rate limiting

`429` responses carry no retry hint. Apply exponential backoff, and treat a monthly quota exhaustion as terminal until the quota resets — see [Rate Limits](/api-reference/api-reference/rate-limits.md) for the schedule.

## Webhook delivery failures

Errors on *your* endpoint follow a separate retry policy: up to 3 attempts with 1s / 4s / 16s backoff on `5xx`, `408`, `429` and transport errors; any other `4xx` is terminal with no retry. See [Webhooks](/api-reference/api-reference/webhooks.md#delivery-behavior).
