Backend Node.js

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.

12 min
Node.js Stripe Webhooks APIs

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

  1. Idempotencia: Guarda el ID del evento para evitar procesar el mismo evento dos veces
  2. Respuesta rápida: Responde 200 inmediatamente y procesa en background
  3. Retry logic: Stripe reintenta eventos fallidos automáticamente
  4. 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