Skip to content

Integración de Webhooks

Los webhooks permiten a Yastubo reaccionar a eventos que ocurren fuera de su sistema, como pagos exitosos, fallos de cobro o cancelaciones de suscripciones en Stripe. El sistema utiliza una arquitectura asíncrona e idempotente para asegurar que cada evento se procese exactamente una vez.

  • Procesamiento Idempotente: Garantizamos que el mismo evento no se procese dos veces gracias al registro de StripeEvent.
  • Seguridad de Firma: Verificación automática de firmas para evitar ataques de suplantación.
  • Transiciones de Estado Automáticas: La póliza cambia de estado (ej. ACTIVE, IN_ARREARS) según los eventos de pago.
  • Conversión de Leads: Los prospectos se convierten automáticamente en clientes finales tras el primer pago exitoso.

El controlador principal reside en app/modules/payments/webhook_handler.py.

El flujo de trabajo para cada webhook recibido sigue estos pasos:

  1. Chequeo de Idempotencia: Buscamos el ID del evento en nuestra base de datos. Si ya existe, abortamos.
  2. Despacho por Tipo: Dependiendo del event_type, delegamos a una lógica específica.
  3. Persistencia de Evento: Al finalizar con éxito, marcamos el evento como procesado.
# Lógica clave de idempotencia en handle_stripe_event
res = await db.execute(select(StripeEvent).where(StripeEvent.event_id == event_id))
if res.scalar_one_or_none():
logger.info(f"Stripe event {event_id} ya procesado. Ignorando.")
return
EventoAcción en Yastubo
payment_intent.succeededMarca la transacción como exitosa y activa la póliza.
payment_intent.payment_failedIncrementa el contador de intentos y notifica al cliente.
customer.subscription.deletedCancela la suscripción y cambia la póliza a estado CANCELLED.
invoice.payment_succeededRegistra el pago recurrente de una suscripción activa.

Ejemplo Práctico: Añadir un Nuevo Evento

Section titled “Ejemplo Práctico: Añadir un Nuevo Evento”

Si deseas manejar el evento charge.refunded para gestionar reembolsos automáticos:

app/modules/payments/webhook_handler.py
elif event_type == "charge.refunded":
charge_id = data_obj.get("id")
# Lógica para marcar transacción como reembolsada
await process_refund(db, charge_id)
# Registrar el evento procesado
db.add(StripeEvent(event_id=event_id, event_type=event_type))
await db.commit()

Webhook Integration Flow