---
title: Rate limits
description: How Verifycate throttles API requests and how to handle HTTP 429
group: Guides
---

# Rate limits

# Rate limits

To keep the API reliable for every workspace, Verifycate limits how quickly clients may send requests. Limits use fixed time windows and apply per client identity (IP, API key, or IP plus email for OTP).

Rate-limited requests return HTTP **429** with error code `rate_limited`. Integrations should treat 429 as temporary and retry after waiting.

## Response

When a limit is exceeded:

| Signal | Meaning |
| --- | --- |
| Status | `429 Too Many Requests` |
| Body `code` | `rate_limited` |
| Header `Retry-After` | Integer seconds to wait before retrying |

Example body (`application/problem+json`):

```json
{
  "title": "Too Many Requests",
  "status": 429,
  "detail": "rate limit exceeded; retry later",
  "code": "rate_limited"
}
```

Example headers:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/problem+json
```

## How to handle limits

1. Detect `status === 429` (and optionally `code === "rate_limited"`).
2. Read `Retry-After` and wait at least that many seconds before retrying the same request.
3. Prefer backing off or queueing outbound calls so you stay under the average rate, instead of hammering the API until you hit 429.

A common pattern is a request queue that only sends the next call when the previous response was not 429 (or after the `Retry-After` delay).

See also [Errors](/docs/api/errors) for the shared problem+json shape.

## Default limits

These are the default ceilings. Values may change as we balance demand and reliability; always rely on `Retry-After` rather than hard-coding sleep times.

| Bucket | Applies to | Limit |
| --- | --- | --- |
| API key | Authenticated requests using a workspace API key (`Authorization: Bearer vc_…`) | 120 requests / minute per key |
| Default | Session/JWT and other authenticated app traffic | 300 requests / minute per IP |
| Public | Public certificate view/verify, request forms, corrections, public workspace/media | 60 requests / minute per IP |
| OTP request | `POST /api/v1/auth/otp/request` | 5 requests / 15 minutes per IP + email |
| OTP verify | `POST /api/v1/auth/otp/verify` | 10 requests / 15 minutes per IP + email |

`GET /api/v1/health` is not rate limited.

For API integrations, the **API key** row is the one that matters day to day. Stay around **2 requests per second** sustained if you issue or send in bulk; short bursts are fine until the per-minute window fills.

## Tips for bulk work

- Prefer batch endpoints (for example [Import issues](/docs/api/issues/import) and [Bulk recipient actions](/docs/api/issues/bulk)) over many tiny calls.
- When paging with [Pagination](/docs/api/pagination), space list requests or reuse a single client with backoff.
- Do not share one API key across unrelated high-volume jobs if you need independent budgets; create separate keys per integration.
