Cómo integrar webhooks de Stripe en tu aplicación Node.js
Guía completa para implementar webhooks de Stripe de manera segura en tu backend con Node.js, incluyendo validación de firmas y manejo de eventos.
Los webhooks son fundamentales cuando trabajas con Stripe. Te permiten recibir notificaciones en tiempo real sobre eventos importantes como pagos exitosos, suscripciones canceladas o disputas iniciadas.
¿Por qué necesitas webhooks?
Cuando un usuario realiza un pago en tu aplicación, el proceso no siempre es instantáneo. Los webhooks te permiten:
- Confirmar pagos de manera asíncrona
- Actualizar el estado de órdenes automáticamente
- Manejar reintentos de pagos fallidos
- Procesar reembolsos y disputas
Configuración inicial
Primero, instala el SDK de Stripe:
npm install stripe
Configura tu endpoint básico:
const express = require("express");
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
const app = express();
// IMPORTANTE: usa express.raw() para webhooks
app.post(
"/webhook",
express.raw({ type: "application/json" }),
async (req, res) => {
const sig = req.headers["stripe-signature"];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET,
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`, err.message);
return res.sendStatus(400);
}
// Manejar el evento
switch (event.type) {
case "payment_intent.succeeded":
const paymentIntent = event.data.object;
console.log("PaymentIntent was successful!");
await handleSuccessfulPayment(paymentIntent);
break;
case "payment_method.attached":
const paymentMethod = event.data.object;
console.log("PaymentMethod was attached to a Customer!");
break;
default:
console.log(`Unhandled event type ${event.type}`);
}
res.json({ received: true });
},
);
Validación de firmas
La validación de firmas es crucial para la seguridad:
const verifyWebhookSignature = (payload, signature) => {
try {
return stripe.webhooks.constructEvent(
payload,
signature,
process.env.STRIPE_WEBHOOK_SECRET,
);
} catch (err) {
throw new Error(`Webhook Error: ${err.message}`);
}
};
Manejo de eventos comunes
Pago exitoso
async function handleSuccessfulPayment(paymentIntent) {
const orderId = paymentIntent.metadata.order_id;
await Order.updateOne(
{ _id: orderId },
{
status: "paid",
paymentIntentId: paymentIntent.id,
paidAt: new Date(),
},
);
// Enviar email de confirmación
await sendConfirmationEmail(paymentIntent.receipt_email, orderId);
}
Suscripción actualizada
async function handleSubscriptionUpdate(subscription) {
await Subscription.updateOne(
{ stripeSubscriptionId: subscription.id },
{
status: subscription.status,
currentPeriodEnd: new Date(subscription.current_period_end * 1000),
},
);
}
Testing local con Stripe CLI
Instala Stripe CLI y ejecuta:
stripe login
stripe listen --forward-to localhost:3000/webhook
Esto te dará un webhook secret para desarrollo y reenviará eventos a tu servidor local.
Mejores prácticas
- Idempotencia: Guarda el ID del evento para evitar procesar el mismo evento dos veces
- Respuesta rápida: Responde 200 inmediatamente y procesa en background
- Retry logic: Stripe reintenta eventos fallidos automáticamente
- Logging: Registra todos los eventos para debugging
Conclusión
Los webhooks de Stripe son esenciales para construir aplicaciones de pago robustas. Con esta implementación, tu backend podrá manejar eventos de pago de manera segura y confiable.
¿Tienes dudas sobre webhooks? Déjame un comentario.
¿Te gustó este artículo?
Suscríbete para recibir más contenido sobre desarrollo web y programación
Contáctame