# Idempotency

Send an `Idempotency-Key` on every `POST` that creates or sends something.

```bash title="cURL"
curl https://api.lelemon.cl/v2/contact-events \
  -H "Authorization: Bearer $LELEMON_API_KEY" \
  -H "Idempotency-Key: inactive-30-cust-88123-2026-11" \
  --json '{ "type": "customer.inactive_30_days", "contact": { "externalRef": "cust-88123" } }'
```


| Situation | Result |
| --- | --- |
| Same key, same request | The stored response, with the header `Idempotent-Replayed: true`. Nothing happens twice |
| Same key, different body | `409 idempotency_key_reused` |
| Same key while the first request still runs | `409 idempotency_key_in_use` |
| The first request ran and failed (`4xx` or `5xx`) | The stored failure, with `Idempotent-Replayed: true`. The effect is not repeated |
| The person in the stored response was suppressed (Ley 21.719 erasure) | `409 idempotency_key_reused`. The stored response is erased; send the request again with a new key |
| The first request was rejected before it ran (authentication, a body that fails validation, an id in the path that does not exist) | The key is free again, so you can fix the request and retry |

Once a request starts running, Lelemon stores its final response, whether it is `2xx`, `4xx` or `5xx`, and a retry with the same key gets that same response. This keeps a message or a webhook that already went out from going out again after an error. To retry a failed operation on purpose, use a new key.

The response is stored for at most 24 hours per organization and key, and it is erased earlier if the person it describes is suppressed. A response that is not JSON, or is larger than 512 KB, is not stored. `PATCH` and `DELETE` ignore the key. A replay of a create returns the stored response without the `secret` field: the secret of a key or a webhook endpoint is shown once, in the first response, so keep it from there.

The `Idempotency-Key` protects one HTTP request from running twice. It does not know your business. Two different requests that mean the same thing, such as refunding order A-1 twice with two different keys, run twice. When an operation must happen once, put the key of the business inside it: pass your own reference (`orderId`, `refundId`) in the arguments of the action and make your endpoint answer the same for a reference it already processed. You choose that key. Lelemon cannot guess it, and an agent that asks twice for the same refund does not have one.

Build the key from what makes the operation unique in your system, such as `inactive-30-cust-88123-2026-11`. A random id per attempt defeats the purpose.

The [TypeScript SDK](/tools/sdk) generates a key for each `POST` and reuses it on its own retries. Pass `idempotencyKey` in the request options to use yours.
