DEV Community

Cover image for Cómo Capturar y Validar Webhooks de Stripe en CI con Apidog
Roobia
Roobia

Posted on • Originally published at apidog.com

Cómo Capturar y Validar Webhooks de Stripe en CI con Apidog

Un cliente paga, Stripe envía un evento payment_intent.succeeded a tu backend y tu endpoint debe marcar el pedido como pagado. Si el manejador falla, el webhook puede recibirse sin que el flujo comercial se complete. El resultado suele aparecer tarde: un ticket de soporte indicando que el pago se realizó, pero la cuenta o el pedido siguen como impagados. La solución es añadir una prueba de CI que compruebe que el evento llegó, se procesó y produjo el cambio esperado.

Prueba Apidog hoy

El reto es que un webhook es una llamada HTTP entrante desde Stripe, no una solicitud que tu prueba envía y espera responder. La mayoría de herramientas de pruebas de API están orientadas al flujo contrario. Para automatizarlo en CI, captura el evento en tu backend, persístelo y consulta ese registro desde la prueba. Esta guía muestra ese enfoque con Apidog. Para una introducción general, consulta la guía sobre cómo probar webhooks y la documentación de webhooks de Stripe.

La restricción que debes considerar

La documentación de Apidog indica que Apidog no soporta de forma nativa la escucha de webhooks. No puedes configurar una URL de Apidog como receptor público de Stripe y esperar que capture eventos entrantes en tiempo real.

El patrón compatible es:

  1. Stripe llama a tu endpoint.
  2. Tu endpoint verifica y registra el evento.
  3. Apidog consulta ese registro.
  4. La prueba valida el evento y sus efectos en el sistema.

Esto convierte un flujo asíncrono en una aserción repetible: en lugar de intentar interceptar la entrega, consultas un estado persistido.

Arquitectura del patrón: capturar y luego consultar

Implementa estas cuatro piezas:

  1. Crea un endpoint backend que reciba los webhooks de Stripe.
  2. Guarda cada evento en una tabla, por ejemplo stripe_event_logs.
  3. Configura la conexión a esa base de datos en el entorno de Apidog.
  4. Usa un Post-Request Processor para consultar y validar el evento almacenado.

Tu aplicación es responsable de recibir, validar y persistir. Apidog entra después: ejecuta SQL contra la base de datos del entorno y decide si el escenario pasa o falla.

Paso 1: crear el endpoint receptor de Stripe

Stripe necesita una ruta pública que acepte solicitudes POST. El endpoint debe conservar el cuerpo sin transformar para validar la firma.

Ejemplo mínimo con Express:

import express from "express";
import Stripe from "stripe";

const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

app.post(
  "/webhooks/stripe",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    let event;

    try {
      event = stripe.webhooks.constructEvent(
        req.body,
        req.headers["stripe-signature"],
        endpointSecret
      );
    } catch (err) {
      return res.status(400).send(`Signature check failed: ${err.message}`);
    }

    // Persiste el evento para que la prueba pueda consultarlo.
    await db.query(
      `INSERT INTO stripe_event_logs (event_id, type, payload, handled_at)
       VALUES ($1, $2, $3, now())
       ON CONFLICT (event_id) DO NOTHING`,
      [event.id, event.type, JSON.stringify(event.data.object)]
    );

    if (event.type === "payment_intent.succeeded") {
      const intent = event.data.object;
      await markOrderPaid(intent.metadata.order_id);
    }

    res.json({ received: true });
  }
);
Enter fullscreen mode Exit fullscreen mode

Puntos importantes:

  • Usa express.raw() en esta ruta. Si un middleware JSON transforma el cuerpo antes de constructEvent, la verificación de firma puede fallar.
  • Verifica siempre stripe-signature antes de procesar el evento.
  • Guarda event.id, event.type, el payload y una marca de tiempo.
  • Usa ON CONFLICT (event_id) DO NOTHING para soportar reintentos y entregas duplicadas de Stripe.

Para profundizar en este requisito, revisa la guía sobre verificación de firma de webhook.

Paso 2: conectar la base de datos en el entorno de Apidog

Configura una conexión de base de datos en el entorno de Apidog que usará CI.

Por ejemplo:

  • El escenario de CI apunta a staging.
  • Stripe entrega el webhook al backend de staging.
  • El endpoint guarda el evento en la base de datos de staging.
  • El Post-Request Processor consulta esa misma base de datos.

La base de datos consultada debe coincidir con el entorno donde se procesa el webhook. Si disparas el pago en staging pero consultas otra base de datos, la prueba no encontrará el evento aunque el endpoint funcione correctamente.

Paso 3: disparar el evento y consultar el registro

Un escenario de prueba para payment_intent.succeeded puede seguir este flujo:

  1. Crea y confirma un pago en modo de prueba de Stripe, o envía un fixture conocido a tu endpoint.
  2. Espera a que Stripe entregue el webhook a /webhooks/stripe.
  3. Ejecuta un Post-Request Processor que consulte stripe_event_logs.
  4. Valida que el evento y los efectos de negocio sean correctos.

Consulta SQL inicial:

SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE type = 'payment_intent.succeeded'
ORDER BY handled_at DESC
LIMIT 1;
Enter fullscreen mode Exit fullscreen mode

No te limites a validar el tipo del evento. Comprueba como mínimo:

  • event_id coincide con el evento que disparaste.
  • type es payment_intent.succeeded.
  • El monto del payload coincide con el cobro esperado.
  • handled_at tiene valor.
  • El pedido asociado cambió a estado pagado.

Por ejemplo, añade una segunda consulta para verificar el efecto comercial:

SELECT id, status, paid_at
FROM orders
WHERE id = :order_id;
Enter fullscreen mode Exit fullscreen mode

La aserción debe confirmar que:

status = paid
paid_at IS NOT NULL
Enter fullscreen mode Exit fullscreen mode

Así validas la cadena completa: entrega, registro, procesamiento y actualización del pedido.

Gestionar el retraso de entrega

Los webhooks son asíncronos. Si consultas la tabla inmediatamente después de desencadenar el pago, puedes crear una condición de carrera: la consulta ocurre antes de que Stripe entregue el evento.

Añade una de estas estrategias antes de fallar la prueba:

  • Una espera breve.
  • Un sondeo que repita la consulta varias veces.
  • Un límite de tiempo con reintentos.

La lógica esperada es:

repetir hasta N intentos:
  consultar stripe_event_logs por event_id

  si existe el evento:
    ejecutar aserciones
    terminar correctamente

  esperar un intervalo corto

fallar si el evento no aparece
Enter fullscreen mode Exit fullscreen mode

Usa el event_id específico cuando sea posible. Consultar solo el último evento de un tipo puede devolver datos residuales de otra ejecución.

Desarrollo local: reenvío de eventos en tiempo real

El patrón de captura y consulta es ideal para CI. Durante el desarrollo local, Stripe no puede llamar directamente a localhost, por lo que necesitas un relé.

El CLI de Stripe puede reenviar eventos a tu endpoint local:

stripe listen --forward-to localhost:3000/webhooks/stripe
Enter fullscreen mode Exit fullscreen mode

También puedes usar Ngrok para exponer un puerto local mediante una URL pública registrada en Stripe.

Usa cada enfoque para su objetivo:

  • CLI de Stripe o Ngrok: desarrollo local y depuración en tiempo real.
  • Registro en base de datos + Post-Request Processor: pruebas automatizadas en CI.

No confundas este flujo con la función Webhook de Apidog

Apidog tiene una función llamada Webhook, pero no sirve para recibir los eventos entrantes de Stripe.

La función nativa Webhook se usa para definir y documentar webhooks salientes: notificaciones que tu propio sistema envía a una URL externa cuando ocurre un evento.

Para documentar un webhook saliente en Apidog:

  1. Haz clic en el icono + de la barra lateral.
  2. Selecciona New Other Protocol APIs y después Webhook.
  3. Configura Request Method, Webhook Name, Debug URL y Other Info.
  4. Haz clic en Save.

Puedes usar Debug URL y Send para simular la entrega durante pruebas. Ten en cuenta que Debug URL solo se usa para depuración y no aparece en la documentación publicada ni en una exportación OpenAPI.

Para más contexto sobre este tipo de diseño, consulta la guía sobre webhooks en el diseño de API.

Endurecer la prueba

Cuando el escenario básico funcione, añade controles para evitar falsos positivos.

1. Valida el evento exacto

No compruebes únicamente:

WHERE type = 'payment_intent.succeeded'
Enter fullscreen mode Exit fullscreen mode

Incluye el identificador del evento o un identificador correlacionado con la ejecución:

SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE event_id = :event_id;
Enter fullscreen mode Exit fullscreen mode

Esto evita que una prueba apruebe por un evento generado en una ejecución anterior.

2. Limpia o aísla los datos de prueba

Puedes truncar la tabla antes de cada ejecución de prueba:

TRUNCATE TABLE stripe_event_logs;
Enter fullscreen mode Exit fullscreen mode

O, si compartes entorno, filtra por un identificador de ejecución:

SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE payload->>'test_run_id' = :test_run_id;
Enter fullscreen mode Exit fullscreen mode

3. Prueba rutas de fallo

Incluye casos negativos:

  • Firma inválida.
  • Tipo de evento inesperado.
  • Payload sin el order_id requerido.
  • Evento duplicado.
  • Error al actualizar el pedido.

Para una firma inválida, verifica que el endpoint responda con 400 y que no se procese el evento.

Para un evento duplicado, verifica que no se creen registros duplicados y que el pedido no se procese dos veces.

Las mejores prácticas de webhook de pago incluyen más consideraciones sobre idempotencia y reintentos.

4. Valida el resultado de negocio

“El webhook llegó” no es suficiente. Una prueba útil debe confirmar que el sistema ejecutó la acción esperada.

Si el webhook debe activar una actualización de pedido, una emisión de factura o una provisión de acceso, consulta y valida también ese estado final.

Ejecutar el escenario desde CI con la CLI de Apidog

Una vez guardado el escenario, ejecútalo sin interfaz gráfica con la CLI de Apidog.

Instalación y autenticación:

npm install -g apidog-cli
apidog login --with-token <YOUR_ACCESS_TOKEN>
Enter fullscreen mode Exit fullscreen mode

Ejecuta el escenario contra el entorno configurado:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t <SCENARIO_ID> -e <ENV_ID> -r cli
Enter fullscreen mode Exit fullscreen mode

Parámetros principales:

  • -t: ID del escenario de prueba.
  • -e: ID del entorno.
  • -r: reportero de resultados.

Para generar un informe HTML junto con la salida de consola:

apidog run \
  --access-token $APIDOG_ACCESS_TOKEN \
  -t <SCENARIO_ID> \
  -e <ENV_ID> \
  -r html,cli
Enter fullscreen mode Exit fullscreen mode

Si una aserción falla, el comando devuelve un código de salida distinto de cero. Eso permite bloquear una fusión o detener un despliegue cuando el flujo de pago deja de procesar correctamente los webhooks.

Consulta la guía de instalación de la CLI de Apidog y el tutorial de pipeline de CI/CD para integrar este comando en GitHub Actions.

Preguntas frecuentes

¿Puede Apidog recibir un webhook de Stripe directamente?

No. Apidog no soporta de forma nativa la escucha de webhooks entrantes. Debes recibir el evento en tu backend, almacenarlo y consultarlo mediante un Post-Request Processor.

Para desarrollo local, usa un relé como el CLI de Stripe o Ngrok.

¿Dónde se ejecutan las aserciones?

En el Post-Request Processor asociado a una solicitud de tu escenario. Ese paso consulta la tabla de eventos mediante la conexión de base de datos configurada en el entorno y compara los resultados con los valores esperados.

¿Cómo gestiono el retraso entre el desencadenamiento y la entrega?

Añade una espera breve o implementa reintentos por sondeo antes de consultar la tabla. La prueba no debe asumir que el webhook se entrega de forma instantánea.

Si necesitas una introducción a pruebas asíncronas, empieza por cómo probar webhooks.

¿La función Webhook de Apidog sirve para este caso?

No para recibir eventos de Stripe. Esa función sirve para diseñar y documentar tus propios webhooks salientes. La validación de eventos entrantes requiere el patrón de captura, persistencia y consulta.

Conclusión

No puedes apuntar Stripe directamente a Apidog para capturar eventos en vivo. El flujo compatible y automatizable es:

  1. Recibe el webhook en tu backend.
  2. Verifica su firma.
  3. Registra el evento en stripe_event_logs.
  4. Procesa la lógica de negocio.
  5. Consulta el registro y el estado final desde un Post-Request Processor.
  6. Ejecuta el escenario desde CI con apidog run.

Con este patrón, tu pipeline comprueba en cada ejecución que un evento de pago no solo llegó, sino que actualizó correctamente el pedido.

Top comments (0)