Las pruebas de APIs de pagos deben responder una pregunta que un camino feliz no puede resolver: ¿qué ocurre cuando el cliente no sabe si la operación fue procesada y decide reintentar? Un timeout puede producirse después de que el proveedor autorizó el pago, de modo que repetir la solicitud sin control puede generar un segundo cobro.
Evitar duplicados no depende de una sola aserción ni de confiar en el botón de la interfaz. Requiere validar idempotencia, concurrencia, persistencia, webhooks, conciliación y estados intermedios. Este artículo presenta una estrategia de QA aplicable a integraciones de pago reales, sin asumir que todos los proveedores se comportan igual.
Por qué un pago puede duplicarse aunque la API funcione
Una transacción distribuida atraviesa varias capas: aplicación, backend, proveedor, adquirente, red y emisor. El cliente puede perder la conexión mientras el servidor continúa. También puede recibir un timeout del gateway, pulsar nuevamente, reiniciar la aplicación o ejecutar dos solicitudes concurrentes. En cada caso, la ausencia de respuesta no demuestra que el primer intento haya fallado.
La protección debe existir en el servidor. Deshabilitar temporalmente un botón ayuda a la experiencia de usuario, pero no cubre reintentos de red, dos dispositivos o llamadas directas. La API necesita una identidad estable de la intención de pago y reglas claras para devolver el resultado anterior, informar que sigue en proceso o aceptar una operación realmente nueva.
Idempotencia: la base, no la estrategia completa
Una operación idempotente produce un único efecto aunque la misma intención se envíe varias veces. Stripe documenta el uso de claves de idempotencia para repetir solicitudes sin crear una segunda operación. El proveedor conserva el estado y la respuesta asociados a la primera solicitud para esa clave.
Adyen también permite reintentar solicitudes de pago con la misma clave y recomienda UUID. Su documentación señala que una solicitud repetida puede devolver el resultado inicial sin volver a cobrar, e identifica condiciones transitorias que requieren reintento controlado.
QA debe validar la implementación propia y no solo la capacidad del proveedor. La clave puede perderse entre capas, generarse nuevamente en cada intento o reutilizarse para pagos diferentes. También existe riesgo antes de enviar la operación al proveedor, por ejemplo al crear dos órdenes internas con la misma intención.
Matriz de pruebas para evitar cobros duplicados
| Escenario | Ejecución | Resultado esperado |
|---|---|---|
| Reintento idéntico | Misma clave y mismos parámetros | Un solo cobro y respuesta consistente |
| Clave reutilizada | Misma clave con monto o moneda diferente | Rechazo explícito, sin nuevo cobro |
| Concurrencia | Dos solicitudes simultáneas con la misma clave | Una ejecución; la otra espera o recibe conflicto definido |
| Timeout posterior | Proveedor procesa, pero la respuesta no llega | Reintento recupera el resultado original |
| Reintento sin clave | Se repite la intención con identificador nuevo | Riesgo detectado por regla interna o comportamiento documentado |
| Clave vencida | Reintento fuera del periodo de retención | Comportamiento conocido y mitigación de negocio |
Qué validar además de la respuesta del proveedor
Una sola intención y una sola transacción interna
Confirma que la base de datos contenga una intención de pago, un identificador de proveedor y la cantidad esperada de movimientos. El modelo puede guardar varios intentos técnicos, pero debe distinguirlos de una nueva compra. Revisa restricciones únicas, relaciones y estados.
Monto, moneda y unidades menores
Valida que el monto enviado corresponda al pedido y que la conversión a unidades menores sea correcta. Cubre monedas con distintas precisiones, redondeo, comisiones e impuestos. Una operación no está bien porque exista una autorización: debe corresponder exactamente a la obligación del cliente.
Estados y transiciones
Modela estados como creada, pendiente, autorizada, rechazada, capturada, cancelada y reembolsada según el producto. Prueba eventos duplicados y fuera de orden. Una notificación tardía no debería regresar una transacción desde un estado final a uno intermedio ni repetir la entrega de un beneficio.
Webhooks duplicados, tardíos y fuera de orden
Los proveedores suelen reintentar webhooks cuando no reciben confirmación. Envía el mismo evento varias veces y comprueba que el consumidor lo reconozca sin repetir efectos. Después intercambia el orden de eventos permitidos y valida que la actualización dependa de una regla de transición, no solo de la hora de llegada.
Verifica firma, identificador único, respuesta rápida y procesamiento desacoplado cuando aplique. Un webhook aceptado no significa que toda la lógica posterior haya terminado; la observabilidad debe mostrar su recorrido.
Conciliación
Compara el estado interno con la fuente del proveedor y con los movimientos esperados. La conciliación detecta operaciones procesadas cuya respuesta o webhook se perdió. Las pruebas deben cubrir diferencias: pago existente solo en el proveedor, estado interno atrasado, monto distinto y devolución incompleta.
Escenarios de concurrencia que sí encuentran defectos
- dos solicitudes de pago con la misma clave en el mismo instante;
- pago y cancelación concurrentes;
- captura manual mientras llega una captura automática;
- dos reembolsos que juntos exceden el monto capturado;
- webhook y consulta de estado actualizando el mismo registro;
- dos dispositivos intentando pagar la misma orden.
Para cada escenario, define cuál operación puede avanzar, cómo se informa el conflicto y qué invariantes deben mantenerse. Ejecutar solicitudes en paralelo sin comprobar la base de datos y los eventos solo produce ruido.
Cómo automatizar sin ejecutar transacciones reales
Utiliza el sandbox oficial del proveedor y métodos de prueba documentados. Crea datos únicos por ejecución y conserva identificadores para consultar el resultado. Las condiciones difíciles —timeouts posteriores al procesamiento, eventos fuera de orden o degradación— pueden simularse en una capa controlada que respete el contrato.
- Crea una orden con monto y referencia únicos.
- Genera una clave de idempotencia ligada a la intención.
- Ejecuta el primer intento y captura los identificadores.
- Repite o concurre según el escenario.
- Consulta API, persistencia, eventos y estado final.
- Comprueba que el monto total procesado sea el esperado.
Esta cobertura se apoya en la estrategia de pruebas de APIs basada en riesgo, las validaciones más allá del código 200 y los escenarios negativos críticos.
Métricas útiles para una API de pagos
- intenciones con más de un cargo asociado;
- pagos pendientes por encima del tiempo esperado;
- webhooks duplicados y descartados;
- diferencias de conciliación por monto y estado;
- reintentos por proveedor, endpoint y causa;
- tiempo desde autorización hasta confirmación interna.
Errores frecuentes
- Generar una clave nueva después de cada timeout.
- Confiar únicamente en deshabilitar el botón de pago.
- Considerar el webhook como una entrega única y ordenada.
- Validar el proveedor sin revisar el estado interno.
- Usar esperas fijas largas en lugar de consultar el estado.
- Exponer PAN, CVV, tokens o secretos en logs y reportes.
Preguntas frecuentes
¿La idempotencia evita todos los cobros duplicados?
No. Protege reintentos asociados a la misma clave dentro del alcance definido. Si el sistema genera claves nuevas, crea intenciones duplicadas o repite efectos después del pago, todavía puede existir duplicidad.
¿Debo reintentar cualquier error del proveedor?
No. Distingue rechazos definitivos, errores de validación y fallos transitorios. El proveedor y el contrato deben indicar cuándo reintentar, con la misma clave y una estrategia de backoff.
Conclusión
Probar una API de pagos exige seguir la intención desde la primera solicitud hasta el estado conciliado. Idempotencia, concurrencia, webhooks y persistencia deben contar la misma historia: una compra válida produce un único efecto económico. Esa es la evidencia que evita que un timeout aparentemente técnico se convierta en un problema financiero y reputacional.

