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

# Limits and idempotency

> Rate limits, page sizes, and how to retry writes safely.

## Rate limits

Limits apply per key.

| Limit | Live keys | Test keys |
| - | - | - |
| Requests | 300 per minute | 60 per minute |
| Writes (`POST`, `DELETE`) | 120 per minute | 30 per minute |
| Request body | 1 MB | 1 MB |
| Page size | 50 by default, 200 at most | Same |

For both kinds of key, and for requests and writes alike, at most 20 are accepted in the same instant. After a burst like that, capacity comes back steadily at the per-minute rate: for requests, five a second with a live key and one a second with a test key. So a test key that sends 25 requests at once gets `429` on the last five, although it is well under 60 a minute.

Over the limit, you get `429 rate_limited` with a `Retry-After` header giving the seconds to wait. Wait that long, then retry. No other rate-limit headers are sent.

### Flood protection at the edge

Separately from the per-key limits, OSA's network edge blocks any single IP address that sends more than 600 requests a minute. Normal integrations never reach it, because the per-key limits are lower. If you do, the response is a `429` with a plain HTML page, not the JSON error format, and it has no `Retry-After` or `X-Request-Id` header. Treat any `429` without a JSON body as "wait a minute, then retry".

Limits are enforced approximately, so plan to stay comfortably under them rather than at them. If you expect a surge, for example after a declared catastrophe, [contact OSA](/introduction#support): limits can be raised for your firm.

## Idempotency

Networks fail. A request can succeed on OSA's side while your system never sees the response. `Idempotency-Key` makes retrying safe.

It is **required** on the two calls that create work for an adjuster:

* `POST /v1/claims`
* `POST /v1/claims/{id}/assignment`

The invitation calls take no `Idempotency-Key` and are safe to repeat without one. After a timeout, send the same call again: inviting an adjuster whose invitation is already pending answers `409 invitation_pending`, and withdrawing an invitation that is already withdrawn answers `404 not_found`. Either answer means your first request went through.

```bash theme={"system"}
curl https://api.osaconnection.com/v1/claims \
  -H "Authorization: Bearer $OSA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c4e2b9a-1f3d-4e8a-b6c5-0d9e8f7a6b5c" \
  -d @claim.json
```

How it works:

* Generate a new random value, such as a UUID, for each operation, and **store it with the operation** so a retry reuses it.
* OSA matches the key with a fingerprint of the **whole request**: method, path and body. The body is compared as JSON, so the order of an object's fields and the spacing don't matter; any difference in a value does.
* A retry of the same request with the same key within **24 hours** returns the same status code, with the claim's **current** state (so a claim the adjuster accepted in the meantime shows as accepted). Nothing new is created.
* The same key with a different request is refused with `422 idempotency_key_reused`. Never reuse a key for a different request.
* If two identical requests arrive at once, one creates the claim and the other gets the same result.

### After 24 hours

Your `external_id` is the second safety net. It is unique within your firm forever, so re-sending a claim days later returns `409 duplicate_claim` with the existing claim's id instead of creating a copy. A `claim_number` that matches one of your firm's **open** claims sent through the API is also a duplicate. A claim is open from the moment you send it until it is closed in OSA, whatever its assignment status. So a rejected claim's number is still taken: offer that claim to another adjuster instead of sending it again. The `claim_number` check is best-effort: two requests with the same `claim_number` and different `external_id`s that arrive at the same instant can both succeed. The `external_id` check has no such gap. Both checks are made separately for test and live keys, so test claims never collide with live ones.

## Request size and format

Request bodies are limited to 1 MB; larger bodies get `413 payload_too_large`. A body that isn't valid JSON gets `400 malformed_request`. Unknown query parameters are rejected with `422 validation_failed`.

## Retrying

| Response | Retry? |
| - | - |
| Network error or timeout | Yes, with the same `Idempotency-Key` |
| `429` | Yes, after `Retry-After` seconds |
| `5xx` | Yes, with the same `Idempotency-Key` and exponential backoff |
| Other `4xx` | No. Fix the request first; see [Errors](/errors) |


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