# Errors

HTTP status codes and error bodies from the OSINTOne API.

URL: https://osintverse.com/docs/api/errors

Errors return JSON with a human-readable `detail` string and a machine-readable `error` object. Branch on `error.code`; show `error.message`; follow `error.hint`. Validation failures also include an `errors` array.

```json
{
  "detail": "Search not found",
  "error": {
    "code": "not_found",
    "message": "Search not found",
    "hint": "Check the id. Searches are visible only to the account or team that created them.",
    "docs_url": "https://osintverse.com/docs/api/errors"
  }
}
```

## HTTP status codes

| Status | `error.code`           | Meaning                                                                                          |
| ------ | ---------------------- | ------------------------------------------------------------------------------------------------ |
| `401`  | `unauthorized`         | Missing, invalid, disabled, or expired API key.                                                  |
| `402`  | `insufficient_balance` | Insufficient prepaid balance for extra LeakRadar unlocks or OSINT Industries premium modules.    |
| `403`  | `forbidden`            | Account is banned.                                                                               |
| `404`  | `not_found`            | Search not found or not owned by your account.                                                   |
| `409`  | `conflict`             | `Idempotency-Key` already used for a different search.                                           |
| `422`  | `invalid_request`      | Invalid request body, query validation, or provider / input\_type pair.                          |
| `429`  | `rate_limited`         | The key used its 1,000 requests for the day (UTC). `Retry-After` is the seconds until 00:00 UTC. |
| `502`  | `upstream_error`       | Upstream provider or API key verification failure.                                               |
| `503`  | `unavailable`          | Temporarily unavailable. Retry with backoff.                                                     |

## Rate-limit headers

Every response to a request made with an API key carries the key's budget, so you can slow down before you reach a 429:

| Header                | Meaning                                                              |
| --------------------- | -------------------------------------------------------------------- |
| `RateLimit-Limit`     | Requests allowed per UTC day (1,000).                                |
| `RateLimit-Remaining` | Requests left today.                                                 |
| `RateLimit-Reset`     | Seconds until 00:00 UTC, when the count resets.                      |
| `RateLimit-Policy`    | The policy, e.g. `1000;w=86400` (1,000 requests per 86,400 seconds). |

The count resets at 00:00 UTC every day. A `429` adds `Retry-After`, the seconds until that reset.

> **422 is usually a catalog mismatch.** If `POST /v1/search` returns 422, the `provider` does not support that `input_type`. Call `GET /v1/providers` or check the [pricing matrix](https://osintverse.com/docs/pricing).

## Search-level failure vs HTTP error

A **200** response can still have `status: "failed"` or `status: "refunded"`. Those are accepted jobs that did not produce matches — inspect `error` on the search object. HTTP 4xx/5xx means the request never became a billed search (except where documented otherwise).

In the [Python SDK](https://osintverse.com/docs/python), HTTP errors become `AuthenticationError`, `PaymentRequiredError`, `ForbiddenError`, `NotFoundError`, `ValidationError`, or `APIError`. `wait=True` on create also raises `SearchFailedError` / `SearchRefundedError` for terminal job status on HTTP 200.
