Concepto clave
Los webhooks en Stripe son notificaciones HTTP que tu servidor recibe cuando ocurren eventos importantes en el sistema de pagos. Imagina que son como mensajeros que te avisan inmediatamente cuando un cliente paga, cancela una suscripción o falla un cobro recurrente. A diferencia de las consultas API que tú inicias, los webhooks son push notifications que Stripe envía automáticamente.
En el mundo real, es como tener un asistente que te susurra al oído cada vez que algo relevante pasa en tu tienda online. Sin webhooks, tendrías que estar preguntando constantemente "¿ya pagó alguien?" cada pocos minutos. Con ellos, simplemente esperas la notificación y actús en consecuencia, lo que hace tu sistema más eficiente y reactivo.
Cómo funciona en la práctica
Configurar webhooks en Stripe sigue un flujo claro. Primero, defines un endpoint en tu backend (por ejemplo, /webhooks/stripe) que acepte peticiones POST. Luego, en el Dashboard de Stripe, configuras este URL y seleccionas qué eventos quieres recibir, como invoice.payment_succeeded o customer.subscription.deleted.
Cuando ocurre un evento, Stripe envía una petición HTTP a tu endpoint con un payload JSON que incluye todos los detalles. Tu servidor debe verificar la firma del webhook usando una clave secreta para asegurar que realmente vino de Stripe y no de un atacante. Después de verificar, procesas el evento, por ejemplo, actualizando la base de datos o enviando un correo de confirmación.
Código en acción
Aquí tienes un ejemplo básico en Node.js usando Express. Primero, el código inicial sin verificación de firma (inseguro):
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
const event = req.body;
console.log('Evento recibido:', event.type);
// Procesar evento sin verificar
res.json({received: true});
});
app.listen(3000, () => console.log('Servidor en puerto 3000'));Ahora, la versión mejorada con verificación de firma usando la librería oficial de Stripe:
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();
// Middleware para raw body (necesario para firma)
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const sig = req.headers['stripe-signature'];
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
} catch (err) {
console.error('Error de verificación:', err.message);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Manejar el evento
switch (event.type) {
case 'invoice.payment_succeeded':
console.log('Pago exitoso para factura:', event.data.object.id);
// Actualizar estado en tu base de datos
break;
case 'customer.subscription.deleted':
console.log('Suscripción cancelada:', event.data.object.id);
// Desactivar acceso del usuario
break;
default:
console.log(`Evento no manejado: ${event.type}`);
}
res.json({received: true});
});
app.listen(3000, () => console.log('Servidor listo para webhooks'));Errores comunes
- No verificar la firma del webhook: Esto expone tu sistema a ataques donde alguien falsifica eventos. Siempre usa
stripe.webhooks.constructEvento equivalente en tu lenguaje. - Usar el mismo endpoint para desarrollo y producción: Stripe permite configurar endpoints separados. Usa uno local con herramientas como ngrok para pruebas y otro en producción para evitar conflictos.
- No manejar eventos duplicados: Stripe puede reenviar webhooks si no recibe respuesta 200. Implementa idempotencia usando el ID del evento para evitar procesar lo mismo dos veces.
- Olvidar configurar los eventos correctos en el Dashboard: Si no seleccionas eventos como
invoice.payment_failed, no recibirás notificaciones de fallos. Revisa la lista de eventos necesarios para tu caso. - No probar con eventos de prueba: Usa el modo Test de Stripe y envía eventos manuales desde el Dashboard para verificar tu código antes de ir a producción.
Checklist de dominio
- Configuré un endpoint HTTPS en mi servidor que acepta peticiones POST para webhooks.
- Agregué verificación de firma usando la clave secreta de webhook de Stripe.
- Seleccioné y suscribí a los eventos relevantes (ej. facturas, suscripciones) en el Dashboard de Stripe.
- Probé el webhook localmente con ngrok y eventos de prueba desde el Dashboard.
- Implementé lógica idempotente para manejar posibles duplicados de eventos.
- Configuré endpoints separados para entorno de desarrollo y producción.
- Documenté los eventos que manejo y cómo afectan a mi aplicación.
Configura un endpoint de webhook seguro con Stripe
Sigue estos pasos para crear un endpoint funcional que reciba y verifique webhooks de Stripe:
- Crea un nuevo proyecto en Node.js con Express e instala la librería de Stripe usando
npm install stripe express. - Define una ruta POST en
/webhookque useexpress.raw({type: 'application/json'})como middleware para capturar el cuerpo sin procesar. - Obtén tu Webhook Signing Secret desde el Dashboard de Stripe (sección Developers > Webhooks) y guárdala como variable de entorno.
- Implementa la verificación de la firma usando
stripe.webhooks.constructEvent(), manejando errores con un status 400 si falla. - Para al menos dos tipos de eventos (ej.
invoice.payment_succeededycustomer.subscription.deleted), añade lógica que registre en consola un mensaje personalizado. - Prueba tu endpoint localmente usando ngrok para exponer tu servidor y envía un evento de prueba desde el Dashboard de Stripe.
- Recuerda que el cuerpo de la petición debe ser raw, no JSON parseado, para que la verificación de firma funcione correctamente.
- Usa el modo Test de Stripe y la opción "Send test webhook" en el Dashboard para simular eventos sin afectar datos reales.
- Si recibes errores de verificación, verifica que estás usando la misma Webhook Signing Secret que muestra Stripe para tu endpoint.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.