Idempotencia
La idempotencia del gateway está implementada y probada (incluidos 10.000 reintentos concurrentes en dos réplicas con una sola ejecución), pero el servicio aún no está desplegado.
Una red puede fallar justo después de que el CMS aplicó tu operación y antes de que recibas la respuesta. La Idempotency-Key te permite repetir la petición sin miedo a recargar dos veces o bloquear dos veces.
Reglas
- Obligatoria en toda escritura que la declare el contrato (
POST,PUTyDELETEde negocio). Sin ella, 400VALIDACION. - Es un UUID. Genera uno nuevo por cada operación lógica (cada recarga, cada bloqueo) y guárdalo junto a tu registro antes de enviar.
- Se acota por operación: la misma clave en dos operaciones distintas (método y ruta) son dos claves independientes.
- Se recuerda durante 24 horas.
- Solo se guardan las respuestas 2xx. Un 4xx no deja nada guardado: corrige la petición y envíala con una clave nueva.
Qué pasa al reintentar
| Situación | Respuesta |
|---|---|
| Misma clave, mismo cuerpo, la primera terminó bien | La respuesta guardada, idéntica. El CMS no vuelve a ejecutar |
| Misma clave, mismo cuerpo, la primera sigue en curso o su resultado es incierto | 409 IDEMPOTENCIA_EN_CURSO con Retry-After |
| Misma clave, otro cuerpo | 422 IDEMPOTENCIA_CUERPO_DISTINTO. Nada se ejecuta |
| El almacén de idempotencia no está disponible | 503 IDEMPOTENCIA_NO_DISPONIBLE. El CMS no se llama: reintenta con la misma clave tras Retry-After |
El cuerpo se compara en forma canónica, con los decimales exactos: "500.00" y "500.0" son cuerpos distintos.
El 409 IDEMPOTENCIA_EN_CURSO
Si el gateway no puede saber si el CMS ejecutó tu operación (se agotó el tiempo de lectura, se cortó la conexión o el CMS respondió 5xx), retiene la clave durante un tiempo de seguridad (hasta 120 s). Mientras tanto, cualquier reintento con esa clave recibe 409 con Retry-After igual a lo que le queda a la retención:
HTTP/1.1 409 Conflict
Content-Type: application/problem+json
Retry-After: 87
{
"type": "urn:finora:cms-api:idempotencia-en-curso",
"title": "Operación en curso",
"status": 409,
"codigo": "IDEMPOTENCIA_EN_CURSO",
"requestId": "01JBX2Q7M8N9P0R1S2T3V4W5X6"
}
Espera Retry-After y vuelve a enviar la misma petición con la misma clave. Así el CMS aplica su segunda barrera de idempotencia y nunca ejecuta dos veces.
Cuándo reintentar con la misma clave
| Respuesta | ¿Reintentar con la misma clave? |
|---|---|
| Sin respuesta (timeout de tu lado, conexión cortada) | Sí |
409 IDEMPOTENCIA_EN_CURSO | Sí, tras Retry-After |
429 LIMITE_DE_TASA | Sí, tras Retry-After |
502 (CMS_ERROR_INTERNO, CMS_RESPUESTA_INVALIDA, CMS_AUTENTICACION) | Sí: en una escritura el resultado es incierto |
503 (IDEMPOTENCIA_NO_DISPONIBLE, CMS_SATURADO, CMS_NO_DISPONIBLE) | Sí, tras Retry-After |
| 2xx | No hace falta; si lo haces, recibes la misma respuesta |
| 400, 401, 403, 404, 422 | No. Corrige la causa; si vuelves a enviar, usa una clave nueva |
Usa espera exponencial con jitter entre reintentos y un tope de intentos; si se agota, deja la operación marcada para revisión en tu sistema y consulta su estado (por ejemplo, GET /v1/operations/{operationId} o los eventos) antes de volver a intentarlo.
Idempotencia de negocio: la referencia bancaria
La Idempotency-Key protege del reintento del transporte, no de un duplicado de negocio. En las recargas prepago, la llave de negocio es referenciaBancaria, única por cuenta: una segunda recarga con la misma referencia (aunque llegue con otra clave o desde otro cliente) responde 409 RECARGA_DUPLICADA con la operación original:
{
"type": "urn:finora:cms-api:recarga-duplicada",
"title": "Recarga duplicada",
"status": 409,
"codigo": "RECARGA_DUPLICADA",
"detail": "La referencia bancaria ya se usó en esta cuenta.",
"requestId": "01JBX2Q7M8N9P0R1S2T3V4W5X6",
"operacionPrevia": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
}