Idempotencia

Una petición que se corta por timeout no te dice si llegó. Con Idempotency-Key puedes reintentarla sin miedo: la segunda te devuelve la respuesta de la primera, tal cual, en vez de hacer el trabajo otra vez.

Cómo se usa

Manda una cabecera Idempotency-Key con un UUID por cada operación lógica. Vale UUID v4 (aleatorio) o v5 (derivado): si generas la key a partir de un identificador tuyo —por ejemplo el número de expediente— tu reintento produce la misma key sin que tengas que guardarla.

curl -sS "$BELFORT_API/v1/persons"   -H "Authorization: Bearer $BELFORT_KEY"   -H "Idempotency-Key: 8d3f2a1c-5b6e-4d7f-9a0b-1c2d3e4f5a6b"   -H "Content-Type: application/json"   -d '{"externalRef": "EXP-2026-0042", …}'

La ventana es de 24 horas. Pasado ese plazo la misma key vuelve a ser nueva.

Qué pasa en cada caso

Reintento idéntico Devuelve la respuesta original verbatim, con su status original — un 201 sigue siendo 201, no un 200 degradado — y añade Idempotency-Replayed: true.
Misma key, cuerpo distinto 409 IDEMPOTENCY_KEY_REUSED. Se compara un hash de la petición completa, así que reutilizar una key para otra cosa no puede devolverte en silencio la respuesta equivocada.
La primera sigue en vuelo 409 con Retry-After. Dos peticiones simultáneas con la misma key no ejecutan dos veces.
La primera falló La key se libera. Los 402, 429 y 5xx no se cachean: reintentar tiene que poder funcionar.
Key malformada 400 IDEMPOTENCY_KEY_INVALID. Se exige UUID para que dos integraciones no puedan colisionar por usar "1" las dos.

Dónde es obligatoria

En las operaciones que crean algo con consecuencias —o que cuestan dinero— la cabecera no es opcional: sin ella recibes IDEMPOTENCY_KEY_REQUIRED. Hoy son 0:

    En el resto se honra si la mandas. Mandarla siempre no tiene coste y te ahorra pensar cuáles son.

    La excepción deliberada

    POST /v1/persons/{id}/decrypt no es idempotente, y no es un descuido. Cada revelado de datos personales tiene que dejar su propia entrada en la bitácora porque la ley pide constancia de cada acceso, no de cada intención. Si un reintento reprodujera la respuesta guardada, ese acceso no quedaría registrado — la bitácora diría que miraste una vez cuando miraste dos.