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

# Rate limits & idempotency

> Per-key rate limits, 429 handling, and Idempotency-Key replay semantics.

## Rate limits

Limits are per API key:

| Scope                                                 | Limit            | Why                                                                                                                              |
| ----------------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| All requests                                          | **120 / minute** | General ceiling.                                                                                                                 |
| Census writes (`PUT /census`, `POST`/`PATCH` members) | **20 / minute**  | Census writes fan out to rating and (post-enrollment) live records. Batch with `PUT /census` instead of looping `POST /members`. |
| Quote creates (`POST /quotes`)                        | **60 / hour**    | Quotes are persistent records; don't use them as a pricing calculator in a loop.                                                 |

Exceeding a limit returns `429 rate_limited` with a `Retry-After` header (seconds):

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 12

{ "error": "rate_limited", "message": "Rate limit exceeded. Retry after 12 seconds." }
```

Honor `Retry-After` rather than guessing your own backoff; it reflects the actual window. These limits are sized for steady-state integrations (a nightly full-roster sync for hundreds of employers fits comfortably); if a bulk migration needs more, ask your partner engineer for a temporary raise rather than building a throttle dance.

Failed authentication is throttled separately: requests with a missing, malformed, revoked, or unknown API key are limited to 30 attempts per minute per source IP, after which the API returns `429 rate_limited` instead of `401`. Authenticated traffic is unaffected by this limiter. If you see it during development, check that your key is loaded correctly rather than retrying.

## Idempotency

Every `POST` and `PUT` endpoint accepts an `Idempotency-Key` header:

```bash theme={null}
curl -X POST https://www.getprescience.com/api/partner/v1/groups/grp_8c2f41d09a3e/enrollments \
  -H "Authorization: Bearer $PRESCIENCE_API_KEY" \
  -H "Idempotency-Key: enroll-acme-1" \
  -H "Content-Type: application/json" \
  -d '{ "quoteId": "qt_5b9e2c7f10ad", "signatory": { "name": "Dana Park", "email": "dana@acme.com" } }'
```

Semantics:

* **24-hour replay window.** A repeated key within 24 hours returns the **stored response** (same status code, same body) without re-executing anything.
* **Key is free-form.** Any unique string up to 255 chars. UUIDs work; deterministic keys derived from your own entity IDs (`enroll-{companyId}-{quoteId}`) work better, because retries after a process crash regenerate the same key.
* **Scoped to your partner account.** No cross-partner collisions to worry about.

Use it everywhere, but **always** on the calls that create things an employer will see: `POST /groups`, `POST /enrollments`. A timeout is not a failure; the request may have landed. With an idempotency key, the retry answers that question safely. Without one, you're left querying state to find out.

<Note>
  Idempotency replays return the stored response even if it was an error. If you fix a bad request, send the corrected payload under a **new** key.
</Note>
