Documento histórico
Este documento se conserva solo para trazabilidad. Consulte el índice maestro para la fuente vigente.
Documento histórico — no usar como fuente de decisiones actuales
Reemplazado por la versión canónica del 2026-07-11. Conservar solo como trazabilidad histórica.
CU-014: Procesar webhook de pago (Stripe)¶
Caso de uso detallado para el procesamiento del webhook de confirmación de pago de Stripe y la actualización del estado del envío.
Metadatos¶
| Campo | Valor |
|---|---|
| ID | CU-014 |
| Nombre | Procesar webhook de pago |
| Actor primario | Stripe (sistema externo) |
| Actores secundarios | Sistema de Notificaciones, Auditoría |
| Módulo | Pagos |
| Prioridad | Media (Fase 2 — Stripe) |
| Frecuencia esperada | Variable (cada vez que un usuario paga con Stripe) |
| Trazabilidad SRS | RF-049, RN-070, RN-071, RN-072 |
Descripción¶
Cuando un usuario paga un envío a través de Stripe Checkout (Fase 2), Stripe envía un webhook al endpoint POST /api/v1/webhooks/stripe confirmando el pago. El sistema IslaBox:
- Verifica la firma del webhook (seguridad).
- Verifica idempotencia (evita procesar el mismo evento 2 veces).
- Actualiza el estado del
paymentacompletado. - Actualiza el estado de la
consolidationy crea elshipment. - Dispara notificaciones al usuario y al operador.
- Registra auditoría.
Este CU es crítico porque sin él, el sistema no puede confirmar pagos online. En MVP, los pagos son manuales (registrados por el operador), así que este caso se implementa completamente para Fase 2.
Precondiciones¶
- El endpoint está expuesto públicamente con HTTPS válido.
- La firma de Stripe se valida con
STRIPE_WEBHOOK_SECRET. - El evento es de tipo
payment_intent.succeededocheckout.session.completed. - El
payment_intent_idestá registrado en la tablapaymentscon estadopendiente.
Postcondiciones¶
Éxito:
- payment.status = completado.
- consolidation.status = pagada.
- shipment.status = en_preparacion (creado).
- Notificación al usuario y al operador.
- Evento en audit_logs.
Fallo:
- HTTP 400 + log de error + alerta a Sentry/Datadog.
- El evento queda en webhook_events con processed = false para reintento.
Flujo principal¶
- Stripe envía
POST /api/v1/webhooks/stripecon:{ "id": "evt_1234567890", "type": "payment_intent.succeeded", "data": { "object": { "id": "pi_1234567890", "amount": 5000, "currency": "usd", "metadata": { "consolidation_id": "55", "user_id": "42" } } } } - El sistema lee el header
Stripe-Signature. - Verifica la firma con
stripe.Webhook.construct_event(). - Si la firma es inválida → HTTP 400 + log de seguridad.
- Busca el evento en
webhook_eventsporevent_id. - Si ya existe y está procesado → HTTP 200 (idempotencia, no reprocesar).
- Si no existe, lo inserta con
processed = false(lock transaccional). - Valida que el
payment_intent_idexista enpayments. - Si no existe → log de error + alerta + HTTP 404.
- Transacción DB:
payments.status = completado,confirmed_at = now()consolidations.status = pagadashipmentsnuevo constatus = en_preparacion
- Llama al servicio de notificaciones (push + email al usuario).
- Marca
webhook_events.processed = true. - Responde HTTP 200 a Stripe en < 5 segundos.
Flujos alternativos¶
FA-1: Evento duplicado¶
- Stripe puede reenviar el mismo evento (reintento por timeout).
- El sistema detecta por
event_idy responde 200 sin reprocesar.
FA-2: Firma inválida¶
- Posible ataque o configuración incorrecta.
- HTTP 400 + log de seguridad + alerta.
FA-3: Pago no encontrado¶
- Si el
payment_intent_idno está en la base: - Log de error crítico.
- Notificación al admin.
- HTTP 404 (Stripe reintentará).
FA-4: Disputa / chargeback¶
- Si llega
charge.dispute.created: - Se crea incidencia automática
pago_duplicadoocobro_indebido. - Se notifica al admin.
- Se congela el envío relacionado hasta resolución.
FA-5: Reembolso desde Stripe¶
- Si llega
charge.refunded: - Se actualiza
payment.status = reembolsado. - Se notifica al usuario.
- Si el envío ya estaba despachado, se abre incidencia para investigar.
Reglas de negocio¶
- RN-070: La firma del webhook es obligatoria; sin firma válida, se rechaza el request.
- RN-071: La idempotencia se garantiza por
webhook_events.event_idcon UK constraint. - RN-072: El procesamiento de un webhook es transaccional: si falla cualquier paso, se hace rollback completo.
- RN-073: El endpoint responde a Stripe en < 5 segundos (SLA de Stripe).
- RN-074: Si el procesamiento tarda > 30s, se delega a un worker asíncrono y se responde 200 inmediato.
Endpoints API¶
POST /api/v1/webhooks/stripe— endpoint público, valida firmaGET /api/v1/admin/webhook-events— vista admin de eventosPOST /api/v1/admin/webhook-events/{id}/replay— reprocesar evento manualmente
Configuración requerida¶
# Variables de entorno
STRIPE_API_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_SUCCESS_URL=https://app.islabox.com/payments/success
STRIPE_CANCEL_URL=https://app.islabox.com/payments/cancel
Eventos generados¶
PAYMENT_CONFIRMEDCONSOLIDATION_PAIDSHIPMENT_CREATEDNOTIFICATION_DISPATCHED
Notificaciones generadas¶
- Push al usuario: "¡Pago confirmado! Tu envío está en preparación"
- Email al usuario con factura PDF adjunta
- Push al operador: "Nuevo envío listo para despacho #1234"