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

# Errors and limits

> Read the error responses, the rate limit and the pagination of the Perquery API.

This page tells you how the Perquery API reports errors, how many requests a key can send, and how to read long lists page by page.

## Error format

The API sends each error as a problem details object (RFC 9457) with the media type `application/problem+json`.

```json theme={null}
{
  "type": "https://perquery.ai/problems/not-found",
  "title": "The resource was not found.",
  "status": 404,
  "detail": "Site not found.",
  "instance": "/v1/sites/0b6f1c3e-5d1a-4c3b-9a7e-2f4d8c1b6a90",
  "correlation_id": "4f9c2d7e8a1b4c6d9e0f1a2b3c4d5e6f"
}
```

| Field | Description |
| - | - |
| `type` | A URL that ends with the error slug. |
| `title` | A short description of the error type. |
| `status` | The HTTP status code. |
| `detail` | A description of this error. |
| `instance` | The path of the request. |
| `correlation_id` | The ID of the request. |

Some errors add more fields. For example, `missing-entitlement` adds `add_on_code`.

> [!TIP]
>
> Use the slug at the end of `type` in your code. The texts of `title` and `detail` can change. The API sends these texts in English.

## Error slugs

| Status | Slug | Cause |
| - | - | - |
| `400` | `bad-request` | The request is not valid. |
| `401` | `unauthorized` | The key is missing, not correct, revoked or expired. |
| `403` | `forbidden` | The request uses a method other than `GET`, or API keys cannot use this endpoint. |
| `403` | `missing-entitlement` | Your organization does not have the API access add-on. |
| `403` | `permission-denied` | The roles of the key creator do not allow this request. |
| `403` | `membership-suspended` | The membership of the key creator is suspended. |
| `403` | `organization-suspended` | Your organization is suspended. |
| `404` | `not-found` | The resource does not exist, or the path is not correct. |
| `406` | `not-acceptable` | The `Accept` header asks for a format other than JSON. |
| `422` | `validation-failed` | A query parameter is not valid. |
| `429` | `usage-limit` | The key sent too many requests. Read [Rate limit](#rate-limit). |
| `500` | `internal-error` | An unexpected error occurred on the server. |

## Validation errors

When a query parameter is not valid, the API answers `422` with the slug `validation-failed`. The `errors` list names each parameter and the problem.

```json theme={null}
{
  "type": "https://perquery.ai/problems/validation-failed",
  "title": "The request body failed validation.",
  "status": 422,
  "detail": "The request content could not be processed.",
  "instance": "/v1/sites/0b6f1c3e-5d1a-4c3b-9a7e-2f4d8c1b6a90/technical/findings",
  "errors": [
    {
      "field": "page_size",
      "reason": "Ensure this value is less than or equal to 100.",
      "code": "max_value"
    }
  ]
}
```

| Field | Description |
| - | - |
| `field` | The name of the parameter. |
| `reason` | A description of the problem. |
| `code` | A short code for the problem, for example `max_value` or `invalid`. |

## Request ID

Each response has an `X-Request-Id` header. Its value is the same as `correlation_id` in an error response. When you contact support about a request, give this ID.

You can send your own `X-Request-Id` header. The value can have 1 to 128 letters, digits, `.`, `_` or `-`. The API then uses your value.

## Rate limit

Each API key can send 600 requests in a window of 60 seconds. The window starts with the first request of the key.

When a key sends more requests, the API answers `429` with the slug `usage-limit`. The response has no `Retry-After` header.

**1. Stop the requests**

When you get `429`, stop sending requests with this key.

**2. Wait**

Wait 60 seconds. The window then starts again.

**3. Send the request again**

Send the request again. If you get `429` again, wait longer before the next try.

> [!TIP]
>
> To stay below the limit, spread your requests over time. Use the `ETag` and `If-None-Match` headers where an endpoint supports them. Read [API introduction](https://docs.perquery.ai/en/api/introduction.md).

## Pagination

Endpoints that return long lists send the list one page at a time. These endpoints accept two query parameters:

| Parameter | Description |
| - | - |
| `page` | The page number. The first page is `1`. The default is `1`. |
| `page_size` | The number of items on a page. The default is `50`. The **Endpoints** reference shows the maximum of each endpoint. |

The response holds the items of the page and these fields:

| Field | Description |
| - | - |
| `total` | The number of items in all pages. |
| `page` | The number of this page. |
| `page_size` | The number of items on a page. |
| `total_pages` | The number of pages. Most paginated endpoints send it. |

The name of the list depends on the endpoint, for example `rows`, `findings` or `pages`. The **Endpoints** reference shows the name for each endpoint.

```bash theme={null}
curl "https://perquery.ai/api/v1/sites/{site_uuid}/technical/findings?page=2&page_size=100" \
  -H "Authorization: ApiKey $PERQUERY_API_KEY"
```

To read all items, start with `page=1`. Increase `page` by one until `page` is equal to `total_pages`. For an endpoint without `total_pages`, stop when the items of all pages reach `total`.

## Related pages

* [API introduction](https://docs.perquery.ai/en/api/introduction.md)
* [Authentication](https://docs.perquery.ai/en/api/authentication.md)


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