Skip to content
FuncionalidadesPreciosAfiliadosBlogAyudaNosotrosContacto
ComenzarIniciar sesión
Volver al Blog
guides2026-08-295 min de lectura

Idempotencia de Webhook: Cuando Stripe Dispara el Mismo Evento de Comisión Tres Veces

La entrega al-menos-una-vez de Stripe implica ~0,3% de eventos duplicados en producción. Cómo el patrón claim de stripe_webhook_events de thMenu maneja duplicados — race condition incluida.

th

thMenu Team

thmenu.com

Durante 14 meses registramos cada webhook de Stripe en thMenu: 312 de 100.000 eventos llegaron con el mismo event_id dos o tres veces. Es la promesa "at-least-once delivery" de Stripe en cifras concretas — sin idempotencia, tres duplicados en tu libro de comisiones.

Por Qué El Mismo Evento Llega Tres Veces

Si Stripe no recibe respuesta 2xx en ~10 segundos, reintenta. Timeouts TCP, cold starts lambda, fallos DNS transitorios, incluso procesamiento exitoso seguido de caída de conexión — todo dispara retries.

Tres escenarios frecuentes: cold start Cloudflare Workers >10s, transacción D1 commiteada pero conexión cortada, o clic manual "resend" en el dashboard Stripe.

El Patrón INSERT-Claim

La defensa de thMenu es la tabla stripe_webhook_events con event_id PRIMARY KEY. Primera acción: INSERT. Error unique constraint 23505 = duplicado — 200 OK no-op.

Crítico: el claim debe preceder a la lógica de negocio para evitar race conditions.

Race Condition: Eventos Fuera de Orden

Incidente real: customer.subscription.updated llegó 800ms antes que checkout.session.completed. UPDATE afectó 0 filas. Fix: rollback del claim, devolver 503, Stripe reintenta.

FAQ

¿Verificar firma antes o después del claim? Antes. Verify es barato, escritura DB cara.

¿Cuánto tiempo retener filas de idempotencia? Stripe garantiza 30 días; nosotros mantenemos 90 días.

¿Stripe reintenta para siempre? No, máximo 3 días.

¿Te resultó útil? Compártelo.