Perdió un cliente por un webhook fallido silencioso
En pocas palabras: Un founder perdió un cliente porque Stripe envió un webhook que su servidor rechazó con error 500 durante un cold start, sin dejar registro. Para evitarlo creó Webhook Proxy, una capa intermedia gratuita hasta 5.000 eventos mensuales que captura fallos, guarda el payload y permite reintentar con un clic.
Un founder que trabaja solo perdió un cliente porque Stripe le mandó un webhook de activación de cuenta y su servidor devolvió un 500 en pleno cold start. No hubo alerta, no hubo log, nada: el evento quedó perdido hasta que el cliente escribió tres días después preguntando por qué pagó y no tenía acceso. Para resolverlo, construyó Webhook Proxy, una capa intermedia gratuita hasta 5.000 eventos por mes.
Los webhooks fallidos silenciosos son eventos que un proveedor como Stripe intenta entregar a tu endpoint, pero que tu servidor rechaza (con un 500) o ignora (por timeout) sin que quede ningún registro visible en tu aplicación. El proveedor sabe que falló. Vos no. Es un problema de plumbing, no de lógica de negocio, y por eso es tan fácil no verlo hasta que alguien reclama.
En este artículo:
- En 30 segundos
- ¿Por qué un webhook puede fallar sin que nadie se entere?
- ¿Cómo funciona Webhook Proxy, la herramienta que evita perder esos eventos?
- ¿Hace falta montar Redis y BullMQ para resolver esto?
- ¿Qué límites tiene el plan gratuito de Webhook Proxy?
- ¿Qué implica esto para founders solos e indie hackers que integran Stripe, Zapier o Make?
- Errores comunes al manejar webhooks de Stripe
- Preguntas Frecuentes
- Conclusión
- Fuentes
En 30 segundos
- Un founder documentó en dev.to cómo perdió un cliente por un webhook de Stripe que devolvió 500 y nunca quedó registrado.
- Webhook Proxy se pone entre Stripe/Zapier/Make y tu endpoint: reemplazás la URL de destino, sin SDK ni cambios de código.
- Guarda el payload JSON crudo de cada evento y permite reintento manual con un clic desde el dashboard.
- El plan gratuito cubre 5.000 webhooks por mes, sin pedir tarjeta, en webhook-proxy-zeta.vercel.app.
- Según la documentación oficial de Stripe, Stripe reintenta entregar un evento hasta por tres días en modo live antes de darlo por perdido.
¿Por qué un webhook puede fallar sin que nadie se entere?
Un webhook falla en silencio cuando tu endpoint devuelve un error o se cuelga justo en el momento en que el proveedor intenta entregarlo, y ese fallo no queda anotado en ningún lado dentro de tu propia aplicación. El caso que relata el autor en su post en dev.to es exactamente ese: Stripe disparó el webhook de activación, el servidor estaba en cold start o en medio de un deploy, devolvió 500, y listo. El cliente ya había pagado.
Lo que hace tan traicionero este tipo de falla es que no rompe nada visible. No hay excepción en tu logging, no hay alerta que te despierte a las 3 de la mañana, no hay nada en tu dashboard de errores. El evento simplemente desaparece de tu campo de visión, aunque técnicamente Stripe sí lo intentó entregar y sí registró el fallo, solo que en su lado, no en el tuyo.
¿Y cómo se enteró el founder de que algo había fallado? Un email del cliente, tres días después, preguntando por qué pagó y nunca tuvo acceso. Ese es el patrón típico: te enterás por reclamo, no por monitoreo.
El riesgo no está solo en tener servidor propio. Si estás encadenando Stripe con Zapier o Make antes de que el evento llegue a tu API, cada salto intermedio es una oportunidad extra de que algo devuelva un error transitorio sin que nadie se entere.
Ejemplo hipotético (ilustrativo, no un caso reportado): imaginemos una plataforma de cursos online chica que cobra con Stripe y usa un Zap de Zapier para crear automáticamente el acceso del alumno en su LMS apenas se confirma el pago. Un día Zapier tarda más de lo habitual en procesar la tarea porque el LMS respondió lento, el zap se marca como fallido en la cuenta de Zapier, pero nadie en el equipo revisa esa bandeja de “history” todos los días. El alumno pagó, Stripe cumplió su parte, Zapier registró el fallo en su propio panel, y el único que no sabe que algo salió mal es el equipo del curso, hasta que el alumno escribe por soporte. El punto de falla acá no fue Stripe ni el código propio: fue el eslabón intermedio que nadie estaba monitoreando activamente.
¿Cómo funciona Webhook Proxy, la herramienta que evita perder esos eventos?
Webhook Proxy es un servicio indie, alojado en Vercel, que se ubica entre el proveedor (Stripe, Zapier, Make) y tu endpoint real para que ningún evento se pierda por un error transitorio. Vos apuntás la URL de destino del webhook al proxy en vez de a tu propio servidor, sin instalar ningún SDK ni tocar código.
El mecanismo, según describe su creador, tiene cuatro piezas concretas:
- Cambio de URL sin fricción: apuntás el webhook al proxy en vez de a tu endpoint. Cero SDK, cero instalación, funciona con cualquier proveedor que te deje configurar una URL de destino.
- Buffer automático: el proxy reenvía cada evento a tu endpoint real y lo retiene si tu servidor responde con 500 o se cuelga en timeout.
- Log JSON en tiempo real: guarda cada payload exactamente como llegó, así podés ver qué se envió realmente en vez de adivinar.
- Reintento manual con un clic: ves el fallo en el dashboard, apretás retry, y el evento se reenvía sin que tengas que tocar nada del lado del proveedor.
No reemplaza tu lógica de backend. Es una red de contención que atrapa lo que tu servidor deja caer. Vale la pena notar que la retención del proxy depende de que el proxy mismo esté disponible: es una capa adicional, no una garantía absoluta, y sigue siendo responsabilidad tuya revisarla de tanto en tanto.
¿Hace falta montar Redis y BullMQ para resolver esto?
No, para la mayoría de los founders solos no hace falta. El consejo clásico de “agregá reintentos” suena bien en un paper de arquitectura, pero implica levantar Redis, sumar BullMQ, escribir lógica de backoff exponencial y armar una dead-letter queue. Es la solución correcta si procesás un millón de eventos por día con un equipo de doce personas. Es un exceso de infraestructura si lo que necesitás es ver “che, esto falló, dale retry”.
El argumento del autor es simple: la mayoría de las fallas de webhooks en proyectos indie no son problemas exóticos de sistemas distribuidos. Son cosas mundanas. Un deploy que tardó 40 segundos de más. Una API downstream que tuvo un hipo de 10 segundos. Para eso no necesitás un sistema de colas, necesitás una red de contención.
Tres preguntas simples para decidir qué te conviene:
- ¿Cuántos eventos recibís por día? Si son decenas o cientos, un proxy con reintento manual alcanza. Si son miles y necesitás procesamiento automático sin intervención humana, ahí empieza a justificarse una cola propia.
- ¿Tenés a alguien dedicado a revisar fallos? Si sos vos solo y ya tenés bastante con el producto, preferí algo que te avise y te deje reintentar con un clic antes que algo que requiera mantenimiento propio.
- ¿Qué tan crítico es el evento que puede perderse? Si hablamos de activación de cuenta pagada, cualquier red de contención (proxy, revisión manual del dashboard de Stripe, o cola propia) es mejor que nada. La pregunta no es si conviene tener alguna, sino cuál conviene según tu volumen.
| Enfoque | Cuándo tiene sentido | Costo de mantenimiento |
|---|---|---|
| Redis + BullMQ + dead-letter queue | Equipos que procesan millones de eventos/día | Alto: requiere infraestructura propia y monitoreo dedicado |
| Webhook Proxy (proxy externo) | Founders solos o equipos chicos con volumen bajo/medio | Bajo: sin código propio, dashboard con reintento manual |
| No hacer nada | Nunca | El costo aparece cuando perdés un cliente |
¿Qué límites tiene el plan gratuito de Webhook Proxy?
El tier gratuito de Webhook Proxy cubre 5.000 webhooks por mes y no pide tarjeta de crédito para arrancar, según describe el propio creador de la herramienta. Podés probarlo directamente en webhook-proxy-zeta.vercel.app.
Ojo con esto: es un proyecto indie hosteado en Vercel, no un producto oficial de la empresa. La fuente no menciona planes pagos ni límites más allá del tier gratuito, así que si tu volumen supera esos 5.000 eventos mensuales, no hay dato público todavía sobre qué pasa después. Habría que consultarlo directo con el creador antes de depender de esto en producción a mayor escala.
¿Qué implica esto para founders solos e indie hackers que integran Stripe, Zapier o Make?
Cualquiera que encadene Stripe con Zapier o Make antes de llegar a su propia API está expuesto al mismo riesgo que describe el artículo fuente: cada salto intermedio es un punto donde un evento puede fallar sin dejar rastro visible en tu lado. No es hipotético, es cuestión de tiempo, como dice el propio autor, y el ejemplo del zap fallido que planteamos arriba muestra que el problema no distingue entre tener servidor propio o depender de un automatismo de terceros.
La documentación oficial de Stripe aclara un matiz importante: Stripe reintenta entregar un evento hasta por tres días en modo live, con backoff exponencial, antes de dejar de intentarlo. En modo sandbox, el reintento es apenas tres veces en el transcurso de unas horas. Ese margen de tres días suena generoso, pero solo te salva si alguien revisa el dashboard de eventos de Stripe con regularidad.
En la práctica, casi nadie revisa ese dashboard todos los días. Subís el proyecto, conectás Stripe, todo funciona en las pruebas, lo mandás a producción y te olvidás de que existe una pestaña de “Event deliveries” hasta que un cliente te escribe enojado.
La documentación de Stripe lista los códigos de error más comunes: 5xx cuando tu servidor falla al procesar, timeout cuando tardás demasiado en responder, y errores de TLS cuando el certificado de tu dominio tiene problemas. Todos esos casos generan reintentos automáticos de Stripe, pero ninguno te avisa proactivamente a vos salvo que entres a mirar.
Un criterio práctico para chequear si estás expuesto: si tu endpoint de webhook nunca devolvió un 5xx según tu propio logging, o revisaste manualmente el dashboard de Stripe y coincide con lo que ves en tu base de datos, probablemente estés cubierto. Si no podés responder eso con certeza ahora mismo, conviene revisar el panel de Stripe hoy mismo, y evaluar si te sirve sumar una capa de reintento manual como la que describe este artículo.
Errores comunes al manejar webhooks de Stripe
- Procesar lógica pesada antes de devolver 200: la documentación de Stripe recomienda responder rápido con un status 2xx antes de ejecutar lógica compleja que pueda causar timeout. Si actualizás inventario, mandás emails y escribís en tres tablas antes de responder, tarde o temprano vas a timeoutear.
- No verificar la firma del webhook: saltarte la validación con el header
Stripe-Signaturey el secretowhsec_deja tu endpoint abierto a que cualquiera te mande payloads falsos. - Confiar solo en el reintento automático de Stripe: los tres días de reintento de Stripe no sirven de nada si nadie mira el dashboard antes de que se agoten.
- Depender del orden de llegada de los eventos: Stripe no garantiza que los eventos lleguen en el orden en que se generaron, algo que la propia documentación aclara explícitamente para casos como suscripciones con múltiples eventos asociados.
- Reenviar manualmente desde el dashboard sin resolver la causa raíz: el reenvío manual no cancela los reintentos automáticos de Stripe, así que podés terminar procesando el mismo evento dos veces si tu lógica no es idempotente.
Preguntas Frecuentes
¿Por qué un webhook de Stripe puede fallar sin que aparezca en mis logs?
Porque el fallo ocurre en la comunicación entre Stripe y tu servidor, y si tu servidor devuelve un 500 o se cuelga por timeout antes de generar cualquier log de aplicación, no queda ningún registro de tu lado. Stripe sí anota el intento fallido en su propio dashboard, pero eso no llega a tu sistema de monitoreo salvo que lo revises manualmente.
¿Qué es un webhook proxy y para qué sirve?
Un webhook proxy es una capa intermedia que se ubica entre el proveedor que envía el evento (Stripe, Zapier, Make) y tu endpoint real, con el fin de capturar y retener eventos si tu servidor falla al procesarlos. Sirve para tener un lugar donde ver el payload crudo y reintentar manualmente sin depender solo del dashboard del proveedor.
¿Necesito Redis y BullMQ para reintentar webhooks fallidos?
No necesariamente, sobre todo si sos un founder solo o un equipo chico con volumen bajo. Redis y BullMQ tienen sentido cuando procesás millones de eventos por día y necesitás backoff exponencial y dead-letter queues; para fallas mundanas como un deploy lento o una API caída diez segundos, un proxy con reintento manual alcanza.
¿Cómo sé si perdí un pago o una activación de cuenta por un error 500?
Revisando la pestaña de Event deliveries en el Workbench de Stripe, donde podés ver si un evento quedó marcado como Failed y el código HTTP de la respuesta de tu endpoint. Si nunca revisaste esa sección, no hay forma de saberlo sin hacerlo, ya que tu propia aplicación no genera ningún registro cuando el fallo ocurre antes de llegar a tu código.
¿Cuánto tiempo reintenta Stripe entregar un webhook antes de darlo por perdido?
En modo live, Stripe reintenta la entrega de un evento hasta por tres días con backoff exponencial, según su documentación oficial. En modo sandbox, el reintento es solo tres veces durante el transcurso de unas horas, un margen mucho más corto que conviene tener en cuenta al probar integraciones.
Conclusión
El caso que documenta el post en dev.to no tiene nada de exótico: es el tipo de falla mundana que le puede pasar a cualquiera que integre Stripe con su propia API, o incluso con un automatismo de Zapier o Make de por medio, y que suele quedar invisible hasta que un cliente reclama. La respuesta no siempre pasa por levantar infraestructura pesada como Redis y BullMQ. Para volumen bajo o medio, revisar con regularidad el dashboard de Event deliveries de Stripe, o sumar una capa liviana como un proxy con reintento manual, cierra la mayoría de esos huecos sin sumar complejidad operativa que no necesitás. Lo que no conviene es seguir asumiendo que “si no hay error en mis logs, no pasó nada”: ese supuesto es exactamente el que le costó un cliente al autor de la fuente.






