Saltar al contenido

Lección 18 de 25 · Lectura y práctica

Procesar Eventos de Suscripción y Facturación

Tipo de lección: VideoConcepto claveLos webhooks de Stripe son notificaciones HTTP que tu servidor recibe cuando ocurren eventos importantes en el sistema de pagos. Imagina que contratas un servicio de seguridad para tu casa: en.

Del concepto a la práctica

Taller de esta lección

Los eventos de suscripción y facturación describen cambios distintos. Un cambio de suscripción puede alterar plan o fecha; un evento de factura informa del documento y su cobro. El procesador debe actualizar solo los campos que cada evento autoriza.

Ejemplo resuelto

customer.subscription.updated cambia el precio de basic a pro y conserva la factura histórica. Después, invoice.payment_succeeded marca la factura del nuevo ciclo como pagada. No se reemplazan ambos estados con una sola variable.

Un timestamp de recepción no determina qué versión está vigente. Stripe no garantiza el orden de entrega: recupera el objeto actual cuando necesites reconciliar y procesa bajo una política que no retroceda periodos pagados. El ID de evento identifica la entrega, no una versión monotónica de la Subscription. Un cambio de precio puede quedar pendiente de pago según payment_behavior; no concede inmediatamente todas las prestaciones por el nombre del evento.

Pruébalo

  1. Define campos separados para plan, ciclo y factura.

  2. Procesa actualización de suscripción.

  3. Procesa pago de factura.

  4. Repite eventos en orden inverso y documenta la regla.

Error frecuente: usar el último evento recibido como verdad absoluta sin revisar su objeto. Corrección: aplica transiciones por tipo y conserva timestamps o versiones.

Comprueba tu resultado

El plan final debe ser pro, la factura del ciclo debe ser paid y el historial anterior permanecer intacto. Un evento duplicado no crea una nueva factura.

Proveedor de pago que envía un webhook verificado al servidor; registro idempotente antes de conceder acceso.
CursaloMapa de práctica
Confirmar el pago en el servidor

El servidor concede acceso a partir de un evento verificado del proveedor y un registro persistente. La pantalla de éxito del navegador es una notificación, no una prueba suficiente de pago. La idempotencia evita duplicar la operación cuando el evento llega más de una vez.

Ver la infografía en tamaño completo ↗
Fuentes para profundizar

Tipo de lección: Video

Concepto clave

Los webhooks de Stripe son notificaciones HTTP que tu servidor recibe cuando ocurren eventos importantes en el sistema de pagos. Imagina que contratas un servicio de seguridad para tu casa: en lugar de revisar constantemente las cámaras (polling), el servicio te llama inmediatamente cuando detecta movimiento (webhook). En suscripciones y facturación, eventos como invoice.payment_succeeded o customer.subscription.updated son cruciales para mantener tu base de datos sincronizada y automatizar procesos.

Stripe envía estos eventos como peticiones POST a un endpoint que configuras, con un payload JSON que contiene toda la información relevante. Tu trabajo como backend developer es verificar que la petición sea auténtica (firmada por Stripe), procesar la información y responder rápidamente para evitar reintentos. Sin webhooks, tendrías que consultar constantemente la API de Stripe, lo que es ineficiente y puede hacerte perder eventos críticos.

Cómo funciona en la práctica

Vamos a desglosar el flujo completo para procesar un evento de factura pagada:

  1. Configuración en el Dashboard de Stripe: En la sección Developers > Webhooks, añades la URL de tu endpoint (ej: https://tudominio.com/api/stripe-webhook) y seleccionas los eventos a escuchar, como invoice.payment_succeeded.
  2. Recepción del evento: Cuando un cliente paga una factura, Stripe envía una petición POST a tu endpoint con un cuerpo JSON. Este incluye un ID único del evento, el tipo (type), y los datos (data.object) con detalles de la factura.
  3. Verificación de firma: Usas la clave secreta de webhook de Stripe para verificar que la petición es legítima, comparando la firma en el header Stripe-Signature.
  4. Procesamiento: Basado en el tipo de evento, actualizas tu base de datos. Por ejemplo, para invoice.payment_succeeded, marcas la factura como pagada y registras la transacción.
  5. Respuesta: Devuelves un código de estado HTTP 200 para confirmar la recepción. Si fallas (ej: error 500), Stripe reintentará el envío según su política.

Código en acción

Aquí tienes un ejemplo en Node.js con Express para manejar webhooks. Primero, instala stripe con npm install stripe.

const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();

// Middleware para parsear el body como raw para verificación
app.post('/api/stripe-webhook', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    // Verificar la firma usando la clave de webhook
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    console.error(`Error de verificación: ${err.message}`);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Manejar el tipo de evento
  switch (event.type) {
    case 'invoice.payment_succeeded':
      const invoice = event.data.object;
      console.log(`Factura ${invoice.id} pagada por ${invoice.customer}`);
      // Aquí actualizarías tu base de datos
      // Ej: marcar factura como pagada, enviar email de confirmación
      break;
    case 'customer.subscription.updated':
      const subscription = event.data.object;
      console.log(`Suscripción ${subscription.id} actualizada`);
      // Ej: sincronizar estado de suscripción en tu sistema
      break;
    default:
      console.log(`Evento no manejado: ${event.type}`);
  }

  res.json({received: true});
});

app.listen(3000, () => console.log('Servidor en puerto 3000'));

Ahora, mejoremos el código para manejar errores de base de datos y evitar procesamiento duplicado. Antes, podríamos procesar el mismo evento múltiples veces si hay reintentos. Después, añadimos un registro de eventos procesados.

// Mejora: Evitar duplicados con un registro simple
const processedEvents = new Set();

app.post('/api/stripe-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) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Verificar si el evento ya fue procesado
  if (processedEvents.has(event.id)) {
    console.log(`Evento ${event.id} ya procesado, ignorando`);
    return res.json({received: true});
  }

  try {
    switch (event.type) {
      case 'invoice.payment_succeeded':
        const invoice = event.data.object;
        // Lógica de negocio: actualizar base de datos
        await updateInvoiceInDB(invoice.id, { status: 'paid' });
        break;
      // Otros casos...
    }
    // Registrar evento como procesado
    processedEvents.add(event.id);
  } catch (dbError) {
    console.error(`Error en procesamiento: ${dbError.message}`);
    return res.status(500).send('Error interno');
  }

  res.json({received: true});
});

Errores comunes

  • No verificar la firma del webhook: Expones tu endpoint a ataques falsos. Siempre usa stripe.webhooks.constructEvent o equivalente en tu lenguaje.
  • Procesamiento lento o con timeouts: Si tu servidor tarda más de unos segundos en responder, Stripe puede reintentar, causando duplicados. Procesa de forma asíncrona si es necesario.
  • Olvidar manejar eventos inesperados: Stripe puede enviar eventos nuevos en actualizaciones. Registra los no manejados para ajustar luego.
  • No probar con eventos de test: Usa el modo test de Stripe y herramientas como el CLI para simular eventos antes de producción.
  • Almacenar la clave de webhook en código: Guárdala en variables de entorno para mayor seguridad.

Checklist de dominio

  1. Configuré un endpoint de webhook en Stripe y lo probé con eventos de test.
  2. Implementé verificación de firma en mi código backend.
  3. Manejo al menos 3 tipos de eventos de suscripción/facturación (ej: invoice.paid, subscription.updated, payment_failed).
  4. Mi endpoint responde con HTTP 200 dentro de 5 segundos para evitar reintentos.
  5. Tengo un registro para evitar procesamiento duplicado de eventos.
  6. Protegí las claves de webhook usando variables de entorno.
  7. Probé el flujo completo con una suscripción real en modo test.

Implementa un webhook para actualizar suscripciones en tu base de datos

En este ejercicio, crearás un endpoint de webhook que maneje eventos de suscripción de Stripe y actualice una base de datos simulada. Sigue estos pasos:

  1. Configura el entorno: Crea un proyecto Node.js con Express. Instala stripe usando npm install stripe express. Define variables de entorno para STRIPE_SECRET_KEY y STRIPE_WEBHOOK_SECRET (usa una clave de test desde el dashboard de Stripe).
  2. Crea el endpoint: Implementa una ruta POST en /webhook que use express.raw para parsear el body. Incluye la verificación de firma con stripe.webhooks.constructEvent.
  3. Maneja eventos clave: Detecta estos eventos: customer.subscription.created, customer.subscription.updated, y customer.subscription.deleted. Para cada uno, registra en consola el ID de suscripción y su nuevo estado (ej: active, canceled).
  4. Simula una base de datos: Usa un objeto en memoria (como un Map) para almacenar suscripciones con su ID y estado. Actualiza este objeto según los eventos.
  5. Prueba con Stripe CLI: Instala Stripe CLI y ejecuta stripe listen --forward-to localhost:3000/webhook. Luego, usa stripe trigger customer.subscription.created para enviar un evento de test y verifica que tu endpoint lo procese correctamente.
  6. Añade manejo de errores: Si la verificación falla, devuelve 400. Si hay error al actualizar la base de datos simulada, devuelve 500 y registra el error.

Entrega el código completo y capturas de pantalla de la consola mostrando los eventos procesados.

Pistas
  • Usa process.env para acceder a las claves de Stripe de forma segura.
  • Recuerda que el body debe ser raw para la verificación; no uses express.json() en esta ruta.
  • Puedes simular una base de datos con const subscriptions = new Map(); y métodos como set y get.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con Implementación Profesional de Suscripciones y Facturación con Stripe

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.