
2 de septiembre de 20266 min de lecturaАдминистратор
Timeout después del cobro: dónde termina la protección de la idempotencia
Cómo vincular la clave de la API con la operación real, sobrevivir a un timeout y evitar que reintentar una solicitud se convierta en un nuevo cobro.
En la idempotencia en pagos, la respuesta más cara de una API a veces parece la ausencia de respuesta. El servidor no esperó el resultado, pero eso no dice nada sobre si el proveedor alcanzó a ejecutar el cobro. Una nueva clave aleatoria ayuda a obtener una nueva respuesta HTTP y, al mismo tiempo, puede crear una segunda operación. Para que el reintento sea seguro, primero hay que acordar qué es exactamente lo que sigue siendo lo mismo.
Dos empleados hacen el mismo reembolso
Imaginemos un error más silencioso: soporte reembolsa 20 euros y, casi al mismo tiempo, el operador financiero reembolsa otros 20 por el mismo caso. Las claves de la API son distintas y ambas solicitudes son técnicamente correctas. La idempotencia del proveedor no detecta aquí que los dos empleados ejecutan una misma instrucción. La protección debe empezar en el expediente interno del reembolso y en una autorización única para ejecutarlo.
Para un reembolso aprobado, cree el registro antes de llamar al proveedor. Ese registro vincula el caso del cliente, el pago original, el monto y el fundamento. El segundo empleado debe ver la acción ya creada, no crear una entidad nueva. Al mismo tiempo, dos reembolsos parciales realmente distintos son legítimos: por ejemplo, por dos productos devueltos. El sistema debe distinguir entre repetir una instrucción y emitir una nueva, por lo que comparar solo el monto no basta.
Empiece por definir una operación
El modelo propuesto separa el número de pedido del número de la acción sobre el pago. Un pedido puede incluir una autorización, varias capturas parciales permitidas y reembolsos separados. Por eso el «número de pedido» es demasiado amplio para todas las solicitudes a la vez, y una clave aleatoria nueva en cada llamada HTTP es demasiado estrecha. Primero cree un registro interno estable de la acción concreta.
Por ejemplo, el pedido hipotético Q-731 prevé un cobro de 48 euros. La clave de negocio interna indica «Q-731, cobro, parte 1». A ella se vinculan el monto, la moneda, el beneficiario, la cuenta del proveedor y la versión de la intención. Para llamar a la API se genera una clave opaca aparte, que se guarda antes del primer envío. Esa misma clave la usan el doble clic, el proceso en segundo plano y el servidor que se recuperó tras una falla. No es necesario incluir datos personales en ella.
La documentación de Stripe sobre solicitudes idempotentes muestra por qué importa tener en cuenta la versión de la API: en la API v1, un reintento devuelve el resultado guardado una vez iniciada la ejecución, incluidas algunas respuestas de error. Las reglas sobre el plazo de conservación de la clave y la comparación de parámetros también forman parte del contrato. No considere cualquier clave como una prohibición indefinida de repetir la operación.
El estado «resultado desconocido» debe ser explícito
- 1.Preparado. La plataforma guardó la acción, sus parámetros y la clave del proveedor. Una restricción de unicidad impide que dos procesadores creen por separado la misma intención.
- 2.Enviado. Un solo ejecutor obtuvo el derecho de enviar la solicitud; los demás ven la operación existente y no crean una nueva.
- 3.Resultado desconocido. La respuesta se perdió o es insuficiente. Es un estado de trabajo propio, no un rechazo confirmado de forma automática.
- 4.Resultado establecido. Una respuesta, un evento verificado o la conciliación prevista confirman el resultado. La plataforma lo registra y ejecuta la acción de negocio correspondiente.
Los nombres de los estados son ilustrativos. En un sistema concreto habrá que distinguir la autorización, la captura, la anulación y otras etapas. Lo esencial es otra cosa: el equipo debe ver lo que quedó sin terminar y conocer la forma permitida de resolverlo. No sustituya la incertidumbre por una clave nueva solo para obtener una respuesta «fresca».
Qué se puede repetir exactamente
Antes de reintentar, compruebe que se trata de la misma operación, con los mismos parámetros relevantes y dentro de las reglas del proveedor. En PayPal, el soporte de PayPal-Request-Id y el plazo de conservación dependen de la API. Un reintento puede devolver el estado actual de la solicitud anterior. Es otra razón para revisar el contrato de cada método concreto en lugar de suponer que todos los SDK de pago se comportan igual.
Si el cliente cambió el contenido del pedido y el monto pasó a 53 euros, eso ya exige una nueva decisión de pago. Primero averigüe qué pasó con la acción anterior de 48 euros. Solo después determine si hace falta una anulación, un cobro adicional o una operación nueva, según el proceso del producto y el consentimiento del cliente. Cambiar sin más el monto en el reintento oculta un cambio importante en la intención de negocio.
En su propio servicio conviene guardar una huella de los parámetros relevantes y rechazar las solicitudes en conflicto que usen la misma clave interna. Decida de antemano qué campos son relevantes: el monto y el beneficiario sin duda requieren atención, mientras que un identificador técnico de trazabilidad normalmente no cambia el sentido del pago. Dé a soporte un mensaje claro sobre el conflicto, sin revelar secretos ni datos de pago completos.
El límite de la protección lo marca el contrato de la API
Adyen describe por separado el alcance de las claves, incluido que no hay una verificación común de duplicados entre algunos endpoints regionales. Por eso, enviar la solicitud por otra ruta no puede considerarse automáticamente el mismo reintento protegido. Menos aún una misma cadena de clave en dos proveedores independientes crea por sí sola una coordinación común.
Conserve el historial interno más tiempo del que vive la solicitud de red y defina un procedimiento para las operaciones antiguas sin resolver. Una vez vencida la ventana garantizada del proveedor, primero hace falta la conciliación. Si no se logra establecer el resultado, asigne un responsable de la excepción y un escalamiento en lugar de intentos interminables.
No oculte las correcciones manuales
Al operador a veces le resulta más cómodo desbloquear una acción atascada que esperar la conciliación. Haga visible esa transición: quién autorizó continuar, qué evidencia estableció el resultado anterior y qué nueva operación reemplaza a la anterior. Editar sin más el estado en la base de datos destruye la relación causal y deja al siguiente turno una historia verosímil pero falsa.
Un recurso útil en la revisión de diseño: enumerar todos los puntos capaces de disparar la acción. El botón del comprador, la tarea programada, el reintento del SDK, la consola de soporte, la recuperación de la cola y el script manual deben converger en un mismo modelo de intenciones. De lo contrario, cada componente evitará bien sus propios duplicados y el sistema en conjunto seguirá creando los de los demás.
En la próxima revisión de la integración, empiece por la pregunta más simple: ¿dónde se guarda la instrucción autorizada de reembolso o cobro? Si la única respuesta es la clave dentro de la solicitud HTTP, la protección empieza demasiado tarde.
Comentarios · 0
Aún no hay comentarios — sé el primero.
Entrar · inicia sesión para comentar.