Webhooks y eventos
El webhook es la fuente de verdad de un pago. El redirect de vuelta del navegador no confirma nada: solo la notificación firmada de la pasarela cambia el estado del Payment.
Ruta
POST /webhooks/:gatewayEl :gateway identifica la pasarela (stripe, redsys, paypal). El core enruta la petición al gateway correspondiente y llama a su parseWebhook.
Qué hace la librería al recibir un webhook
- Verifica la firma sobre el
rawBody(por eso necesitasrawBody: true). Firma inválida →400. - Traduce la notificación a un
WebhookEventgenérico (captured/failed). - Casa el evento con el
Paymentpor sugateway_ref. - Impone idempotencia por
(gateway, event_id): reenviar el mismo evento responde200sin re-procesar. - Emite el evento de dominio correspondiente.
Eventos de dominio
Escúchalos con @OnEvent de @nestjs/event-emitter:
import { OnEvent } from '@nestjs/event-emitter'
import { PaymentEventPayload, PAYMENT_EVENTS } from '@kaizen/payments-gateway'
@Injectable()
export class MiListener {
@OnEvent('payment.captured')
onCaptured(p: PaymentEventPayload) { /* pago confirmado */ }
@OnEvent('payment.failed')
onFailed(p: PaymentEventPayload) { /* pago rechazado */ }
}Estados de un pago
Un Payment recorre estos estados (PaymentStatus):
| Estado | Significado |
|---|---|
pending | Creado; esperando que el usuario complete el pago |
authorized | Autorizado pero no capturado |
captured | Cobrado con éxito (evento payment.captured) |
failed | Rechazado o fallido (evento payment.failed) |
Cómo llevas al usuario a pagar
Sea cual sea la pasarela, POST /payments/charge te devuelve siempre el mismo formato y tú siempre haces lo mismo: redirigir el navegador al redirect_url.
{
"payment_id": "b9c1…",
"gateway": "stripe",
"status": "pending",
"redirect_url": "https://…"
}Lo que hay detrás de ese redirect_url cambia según la pasarela, pero eso lo resuelve la librería, no tú:
| Pasarela | A dónde apunta el redirect_url |
|---|---|
| Stripe | Al Checkout hospedado por Stripe |
| PayPal | A la página de aprobación de PayPal |
| Redsys | A una página que sirve la propia librería y que auto-envía el formulario firmado al TPV |
En Redsys y PayPal, tras pagar, el navegador vuelve por la librería (que finaliza el cobro) y acaba en tu success_url / cancel_url. Detalles en cada pasarela: Stripe, Redsys y PayPal.