Idempotencia
POST /orders mueve dinero, así que es el único endpoint donde un reintento no
puede significar un segundo pago. Para eso está X-Idempotency-Key, y es
obligatorio — no es un nice-to-have.
X-Idempotency-Key: 0190f9b2-3c4d-4e5f-8a6b-7c8d9e0f1a2b
Si lo omites, la request nunca llega a la lógica de órdenes:
{
"message": "\"Missing required request parameters: [X-Idempotency-Key]\"",
"requestId": "92885917-5fb9-41d1-8272-70cfdefe6c23"
}
Ese body lo devuelve el API gateway, no el servicio: el header está declarado como
requerido en el borde, así que la request se rechaza antes de que corra lógica de
órdenes. Es la única forma de error con requestId y sin statusCode — cita ese id
si abres un ticket.
También es tu referencia
La key es un string opaco generado por el cliente — el formato lo eliges tú
y lo reenviamos sin tocarlo. Vuelve en la orden como idempotency_key, que es
el handle con el que después encuentras esa orden:
GET /orders?idempotency_key=0190f9b2-3c4d-4e5f-8a6b-7c8d9e0f1a2b
Así que elige algo con sentido y único en tu sistema — el id de una factura, el id de una corrida de pagos, un UUID que guardas junto al pagadero. Si generas una key al azar y la descartas, descartaste tu propia referencia.
Qué pasa si repites
| Envías | Resultado |
|---|---|
| Misma key, misma request | 201 con la orden original. No se crea nada nuevo. |
| Misma key, request distinta | 409 B2B_IDEMPOTENCY_CONFLICT |
| Key nueva | Una orden nueva |
La primera fila es el comportamiento que quieres después de un timeout, una conexión cortada, o cualquier respuesta que no pudiste leer. Repite la request idéntica con la key idéntica y o creas la orden (si el primer intento nunca llegó) o recibes la que ya tienes.
La segunda fila es señal de un bug, no algo para esquivar: la misma key llegó con datos distintos. No lo reintentes con una key nueva hasta saber cuál de los dos payloads era el que querías.
La otra cosa de uso único
Las keys de idempotencia no son la única regla de unicidad de POST /orders, y
la otra se comporta distinto:
{
"code": "B2B_QUOTATION_ALREADY_USED",
"category": "PERMANENT",
"message": "La cotización referenciada ya respalda otra operación: es de uso único. NO reintente con la misma cotización. Verifique el estado de la operación existente antes de crear una nueva; si corresponde, genere una cotización nueva."
}
Una cotización es de uso único: respalda exactamente una orden, para siempre, sin importar cómo terminó esa orden. Entonces:
- Nunca reintentes con el mismo
quotation_id. Falla idéntico siempre. - Antes de crear una orden de reemplazo, busca la que ya existe. Ya hay una operación en curso o completada contra esa cotización, y crear una segunda es la forma de pagarle dos veces al beneficiario.
Un intento nuevo significa una cotización nueva — lo que también significa una tasa nueva, porque las cotizaciones expiran.
Ningún otro endpoint la usa
X-Idempotency-Key solo aplica a POST /orders. Las lecturas son idempotentes
por naturaleza, y POST /quotations es seguro de repetir: una cotización de más
no cuesta ni compromete nada hasta que una orden la referencia.