Cada mes tu equipo abre la plataforma de cobros, descarga un reporte, lo cruza con el estado de cuenta y busca a mano qué depósito corresponde a qué cliente. Mientras tanto, tu sistema de facturación espera una confirmación que nunca llega porque el webhook se perdió en el camino, o llegó dos veces y nadie lo notó.
Lo que te llevas de este artículo
- Guarda cada evento con su ID único antes de procesarlo, para evitar duplicados.
- Verifica la firma de cada webhook usando la clave secreta que compartiste con el proveedor.
- Responde con HTTP 200 en menos de 5 segundos, procesa en background.
- Implementa idempotencia en tu lógica: si el event_id ya existe, no hagas nada.
Los webhooks son la columna vertebral de cualquier integración de pagos seria. No son una comodidad: son la forma en que tu servidor se entera de que el dinero llegó, sin tener que preguntar cada 10 segundos. Pero un webhook mal implementado causa más problemas que soluciones. Aquí está cómo hacerlo bien desde el primer día.
Qué problema resuelve un webhook bien hecho
Un webhook es una petición HTTP que el proveedor de pagos envía a tu servidor cuando ocurre un evento (un pago confirmado, un reembolso, una dispersión completada). Sin webhooks, tu equipo tiene que sincronizar manualmente o escribir scripts que pregunten cada minuto si hay algo nuevo. Con webhooks, la notificación llega al instante.
Pero «llega» no significa «se procesa correctamente». Si tu servidor estaba caído cuando el webhook llegó, se pierde. Si tu código procesa la misma notificación dos veces porque llegó duplicada, tu cliente aparece con dos facturas. Si alguien falsifica un webhook para simular un pago que no ocurrió, tu sistema lo cree.
Un webhook bien hecho resuelve estos tres problemas: idempotencia (procesar la misma notificación 100 veces da el mismo resultado que una), reintentos inteligentes (el proveedor reintenta si tu servidor no responde), y verificación de firma (solo aceptas notificaciones que vinieron realmente del proveedor).
Qué necesitas antes de empezar
Tu servidor necesita un endpoint HTTP (una ruta como /webhooks/finaxapay) que acepte peticiones POST. Este endpoint debe estar en producción y accesible desde internet, sin autenticación básica (el proveedor no puede pasar usuario y contraseña en cada petición). Necesitas también una clave secreta que solo tú y el proveedor conocen, para firmar y verificar cada notificación.
En tu base de datos, cada evento recibido debe guardarse con un ID único (el event_id que envía el proveedor). Esto es lo que previene procesar dos veces el mismo evento.
Pasos para implementar webhooks correctamente
- Expón un endpoint público que acepte POST. La URL debe estar en tu dominio de producción, sin puertos raros, sin paths secretos. Ejemplo: https://tudominio.com/api/webhooks/finaxapay. Responde siempre con HTTP 200 en menos de 5 segundos, incluso si algo falla adentro.
- Guarda el evento en base de datos antes de procesarlo. Cuando llega la notificación, inserta un registro con el event_id, la carga útil, y un estado «recibido». Luego procesa. Si el servidor se cae a mitad del procesamiento, al reintentar encontrarás el evento ya guardado y no lo procesarás de nuevo desde cero.
- Verifica la firma de cada webhook. El proveedor envía un header X-Signature o similar. Tú recalculas esa firma usando la clave secreta y la carga del webhook. Si no coinciden, rechaza la petición. Esto previene que alguien falsifique un pago.
- Implementa idempotencia en tu lógica de negocio. Antes de crear una factura o marcar un cliente como pagado, pregunta a la base de datos: «¿Ya procesé este event_id?». Si la respuesta es sí, no hagas nada. Si es no, procesa y marca el evento como completado.
- Registra todo lo que pase. Guarda en logs cada webhook que llega, su firma, si pasó validación, y qué acción se tomó. Cuando algo salga mal (y saldrá), esos logs son tu única prueba de qué sucedió.
- Configura el reintentos en el panel del proveedor. Si tu endpoint responde con un código de error (5xx), el proveedor debe reintentar después de 1 minuto, luego 5, luego 10. Define cuántos reintentos permite antes de darse por vencido. Esos reintentos son tu red de seguridad cuando tu servidor estaba caído.
Quién hace qué en un webhook
| Componente | Responsabilidad | Qué falla si no lo haces |
|---|---|---|
| Tu servidor (endpoint) | Recibir, validar firma, guardar evento, responder en menos de 5 segundos | El proveedor lo marca como caído y deja de reintentar |
| Tu base de datos | Almacenar event_id, prevenir duplicados, registrar estado del procesamiento | Procesas el mismo pago dos veces, dos facturas para un cliente |
| Proveedor de pagos | Enviar webhook, reintentar si no recibe 200, firmar cada notificación | Pierdes la notificación, no sabes que el pago llegó |
| Tu lógica de negocio | Verificar que no procesaste el event_id, crear factura, actualizar saldo | Inconsistencia entre pagos recibidos y facturas emitidas |
Errores que descubrirás en producción si no los evitas ahora
Responder lentamente. Si tu endpoint tarda 30 segundos en responder, el proveedor asume que falló y reintenta. Procesa el webhook en background (usa una cola de tareas) y responde con 200 al instante.
No validar la firma. Alguien escribe un script que simula un webhook y se envía a sí mismo dinero ficticio. Tu sistema lo cree porque no verificó que la notificación vino realmente del proveedor.
Olvidar que los reintentos llegan desordenados. El webhook del pago 1 se reintenta tres veces. Mientras tanto, el pago 2 ya llegó y se procesó. Cuando el reintento del pago 1 llega, tu código no debe asumir que es nuevo solo porque llegó después.
Guardar el evento después de procesarlo. Si el servidor se cae entre procesar y guardar, al reintentar procesarás de nuevo. Guarda primero, procesa después.
Cómo FinaxaPay te ayuda aquí
FinaxaPay envía webhooks firmados con cada transacción confirmada, reintentando automáticamente si tu servidor no responde. Tu responsabilidad es implementar idempotencia en tu lado. La documentación completa de la API, con ejemplos de validación de firma y manejo de reintentos, está en finaxapay.site/docs.
Un webhook bien hecho es la diferencia entre una integración que funciona silenciosamente y una que te despierta a las 2 de la mañana porque tu equipo descubrió que procesó el mismo pago tres veces. Implementalo ahora, en desarrollo, no en producción.
Preguntas frecuentes
¿Qué pasa si mi servidor estaba caído cuando llegó el webhook?
El proveedor lo reintenta automáticamente varias veces (según la configuración). Por eso es crítico guardar el event_id: cuando el servidor se levanta, el reintento llega y tu código ve que ya lo procesó, sin duplicar.
¿Cómo verifico que el webhook vino realmente del proveedor?
El proveedor envía un header con una firma (HMAC-SHA256 típicamente). Tú recalculas esa firma usando la clave secreta y la carga del webhook. Si coinciden, es auténtico. Si no, es falsificado.
¿Puedo procesar el webhook lentamente si lo hago en background?
Sí, pero tienes que responder con 200 al instante. Guarda el evento en una cola de tareas (Redis, SQS, etc.) y responde inmediatamente. El procesamiento pesado ocurre en segundo plano.
¿Qué pasa si proceso el mismo webhook dos veces por accidente?
Si implementaste idempotencia (verificas el event_id antes de procesar), no pasa nada: el segundo intento ve que ya existe y se ignora. Sin idempotencia, creas dos facturas para un pago.
¿Dónde encuentro ejemplos de código para validar webhooks?
En la documentación de la API de FinaxaPay (finaxapay.site/docs) hay ejemplos en Node.js, Python y PHP mostrando cómo validar firma e implementar idempotencia.