# Idempotencia

Reintenta cualquier POST sin miedo a crear dos veces el mismo producto, cliente o movimiento.

Lo que creas por la API viaja a las cajas del negocio. Si un `POST` se corta por la red y lo reintentas, podrías crear dos veces el mismo cliente o sumar dos veces el mismo stock. El header `Idempotency-Key` evita eso.

## Cómo funciona

- **Es obligatorio en todo `POST`.** Sin él, la respuesta es `400 IDEMPOTENCY_KEY_REQUIRED`.
- Usa un valor **único por operación**: un UUID nuevo es lo más simple. Admite hasta 255 caracteres entre letras, números y `-` `_` `:` `.`.
- Si reintentas **la misma operación**, reutiliza **el mismo valor**.
- El valor vale **24 horas** y es por API key: dos keys distintas no comparten valores.

```sh
curl https://api.posdata.so/public/v1/inventory/movements \
  -H "Authorization: Bearer $POSDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: compra-OC-2026-0915" \
  -d '{ "product_id": "8d2c1f0a-3b4e-4c5d-9e6f-7a8b9c0d1e2f", "type": "in", "quantity": 24, "reference": "OC-2026-0915" }'
```

## Qué responde la API

| Situación                                                                                      | Respuesta                                                                                                            |
| ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Primera vez con ese valor                                                                      | Se procesa normalmente.                                                                                              |
| Mismo valor y **misma** petición, ya terminada con éxito                                       | La respuesta original, con el mismo código y cuerpo, y el header `Idempotent-Replayed: true`. No se crea nada nuevo. |
| Mismo valor y **otra** petición (otra ruta u otro cuerpo)                                      | `422 IDEMPOTENCY_KEY_REUSED`. Nunca te devolvemos en silencio el resultado de otra operación.                        |
| Mismo valor mientras la primera petición sigue en curso, o si se interrumpió antes de terminar | `409 IDEMPOTENCY_IN_PROGRESS`. Nunca se vuelve a ejecutar.                                                           |

“Misma petición” significa mismo método, misma ruta y mismo cuerpo JSON. El orden de las claves del JSON no importa.

## Solo se guardan los éxitos

Solo se guarda la respuesta de una petición que terminó en **2xx**, y se guarda antes de enviártela. Si la respuesta fue un error (un `400` que vas a corregir, un `409`, un `500`), el valor queda libre: puedes corregir la petición y reenviarla con el mismo `Idempotency-Key` sin recibir `IDEMPOTENCY_KEY_REUSED`. Un error nunca oculta una escritura que sí se hizo: si el cambio quedó guardado, la respuesta es 2xx.

En casos excepcionales, la respuesta 2xx de una escritura trae solo `object` e `id` (el cambio sí quedó guardado, pero no pudimos volver a leerlo en ese instante). Consulta el recurso con un `GET` por su `id`.

## Si recibes `IDEMPOTENCY_IN_PROGRESS`

La primera petición con ese valor está en curso o se interrumpió (por ejemplo, durante un despliegue nuestro). Posdata **no la vuelve a ejecutar**, porque no puede saber si alcanzó a guardar el cambio: repetirla podría, por ejemplo, sumar dos veces el mismo stock.

1. Espera unos segundos y reintenta con el **mismo** valor. Si la primera terminó bien, recibes su respuesta.
2. Si sigue respondiendo `409`, **verifica con un `GET`** si el recurso se creó (por ejemplo, `GET /inventory/movements?product_id=…&created_since=…` y busca tu `reference` entre los resultados, o `GET /customers?email=…`).
3. Solo si **no** se creó, reintenta con un `Idempotency-Key` nuevo.

## ¿Y los PATCH?

Los `PATCH` (editar un producto, una variante, una categoría o un cliente) no llevan `Idempotency-Key`: enviar dos veces el mismo cambio deja el registro igual. Ten en cuenta que en una edición gana el cambio más reciente: si alguien edita el mismo cliente desde una caja entre tus dos intentos, tu reintento lo sobrescribe.

## Recomendaciones

- Deriva el valor de algo que identifique la operación en tu sistema (`pedido-1234-cliente`, `OC-2026-0915`): así, aunque tu proceso se reinicie, el reintento usa el mismo valor.
- Envía también tu propia referencia en el cuerpo cuando el recurso la admita (`reference` en los movimientos): te facilita verificar con un `GET`.
- No reutilices un valor para una operación distinta, aunque hayan pasado más de 24 horas.

---

Fuente: https://developers.posdata.so/idempotencia/ · Índice para agentes: https://developers.posdata.so/llms.txt
