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

# Idempotency

> Retry a request safely: the same key returns the same response, without sending or charging again.

A system that loses a response to a timeout usually resends the request. Without protection, a repeated `POST` creates a duplicate item or sends the same alert twice, charging twice. The `Idempotency-Key` header solves this.

## Where to use it

On two routes, and only on them:

* `POST /establishments/{establishment}/items`
* `POST /establishments/{establishment}/items/{item}/events`

The header is optional, but we recommend always sending it on both.

## How to use it

Generate a unique value for **each operation you intend to perform** (a UUID v4 will do) and send it in `Idempotency-Key`. The value has 1 to 255 visible ASCII characters. On a network failure, repeat the request **with the same key and the same body**.

```bash theme={null}
curl -X POST "$API/establishments/12/items/42/events" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f8e7d6c-5b4a-4c3d-8e2f-1a0b9c8d7e6f" \
  -d '{ "message": "It is here!" }'
```

## What happens

* The **first response** is stored for **24 hours**: a success (2xx) as much as a **business-rule refusal**, that is, any error with its own `code`, such as `insufficient_credits`, `dispatch_in_progress` or `dispatch_too_soon`.
* A repetition with the same key and the same body gets the stored response, byte for byte, with the header **`Idempotent-Replayed: true`** and the original `Content-Language`. Nothing is processed again and nothing is charged again.
* A stored refusal is **not retried**. To try again for real (for example, after buying credits), send a new key.
* `validation_failed`, `forbidden` and server errors (5xx) are **not** stored: fix and repeat, with the same key if you like.
* A replay counts towards the rate limit (see [Conventions](https://docs.needalert.app/en/api/conventions.md)).

> [!NOTE]
>
> Storing business-rule refusals too differs from some payment APIs, which only store successes. Here, a refusal such as `dispatch_too_soon` repeated with the same key stays refused even after the seconds have passed: use a new key.

## Errors of the header itself

| HTTP | `code` | Cause |
| - | - | - |
| 422 | `idempotency_key_reused` | The same key was used with a different body. Each intended operation has its own key. |
| 409 | `idempotency_request_in_progress` | The first request with this key is still being processed. Wait a moment and repeat. |
| 422 | `validation_failed` (field `idempotency_key`) | The value is empty, longer than 255 characters or has characters outside visible ASCII. |


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