# Idempotency and retries

> Retry an identification safely: the Idempotency-Key header makes a repeated request return the first answer, charged once.

Last updated: 2026-09-17

A network can fail after Fingerly has answered but before the answer reaches the client. Retrying then would identify the visitor twice and charge twice. An idempotency key prevents both.

## Idempotency keys

Send a unique `Idempotency-Key` header with `POST /identify`, and send the same value with every retry of that request.

```http Request
POST /api/v1/identify HTTP/1.1
Host: us.api.fingerly.io
Content-Type: application/json
x-api-key: fly_pk_us_production_…
Idempotency-Key: 7d5e1f2a-3c4b-4d6e-8f90-a1b2c3d4e5f6
```

- Keys are scoped to your organization and remembered for at least one hour.
- Use a random UUID. Keys may be up to 255 characters.
- A repeat of a key that was already answered returns `200` with the first `request_id` and `"duplicate": true`, is not charged, and does not count against your rate limit.
- A request refused with `402` or `429` releases its key, so the retry is processed normally.

```json Duplicate response
{
  "request_id": "01a0a84b-e6a2-7c09-9f51-0b3d7a26c8e4",
  "duplicate": true
}
```

> **Tip:** A duplicate response carries only the request ID. Keep the first response, or read the event on your server with [Get an event](https://docs.fingerly.io/reference/get-event).

## How the SDKs retry

| SDK | Attempts | Retries on | Backoff |
| --- | --- | --- | --- |
| JavaScript and web frameworks | 3 | Network errors, timeouts, `408`, `425`, `429`, `5xx` | Full jitter from 100 ms, capped at 2 s |
| iOS and Android | 3 | Network errors, `429`, `5xx` | Full jitter from 100 ms, capped at 2 s |

Every SDK attempt times out after 5 seconds and reuses one idempotency key per `identify()` call.

## Other endpoints

- `GET` requests are naturally safe to retry.
- `POST /events/{request_id}/supplement` deduplicates on content: resending the same deferred report returns `202` with `"duplicate": true`, and a different one returns `409`.
