Saltar al contenido

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

Quiz Final: Evaluación del Proyecto Integrador

Tipo de lección: QuizConcepto claveEn un sistema de suscripciones profesional, el ciclo de vida completo del cliente se gestiona a través de tres componentes principales: suscripciones para pagos recurrentes, Billing APIs para.

Del concepto a la práctica

Taller de esta lección

El proyecto se revisa por factura y periodo, sin confundir una entrega duplicada con un nuevo cobro. El acceso local y los estados de Stripe tienen fuentes distintas que deben reconciliarse.

Ejemplo resuelto

Fixture simulado: usuario Ana vinculado de forma confiable a cus_41 y sub_41; in_90 open; derechos pendientes. Recibes evt_1 subscription.created que describe incomplete; después evt_2 invoice.paid para in_90. Al consultar el objeto vigente, sub_41 está active y la factura pagada corresponde al plan y periodo aceptados. Una transacción registra la concesión y done. Repetir evt_2 no crea otra concesión ni otra notificación.

Pruébalo

  1. Registra cada event.id y el data.object.id correspondiente.

  2. Procesa evt_1 y evt_2 con verificación válida de la simulación o sandbox.

  3. Repite evt_2 y comprueba la restricción única y los efectos.

  4. Añade evt_3 invoice.payment_failed de una factura distinta in_91 del siguiente ciclo, que permanece open.

  5. Interrumpe un procesamiento después de received y demuestra su recuperación antes de marcar done.

Error frecuente: decidir el estado de todas las facturas por el último mensaje recibido. Un fallo de in_91 no convierte in_90 en impagada, ni un viejo invoice.paid reabre una suscripción ya terminada.

Comprueba tu resultado

Hay tres IDs de evento distintos y una entrega duplicada sin efecto. in_90 queda paid; in_91 conserva su estado vigente open. La Subscription y el acceso se determinan por reconciliación y la política documentada de periodo pagado/impago, no por una afirmación automática de active. El informe identifica si el ejercicio fue simulado o ejecutado y no presenta importes demo como cobros reales.

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: Quiz

Concepto clave

En un sistema de suscripciones profesional, el ciclo de vida completo del cliente se gestiona a través de tres componentes principales: suscripciones para pagos recurrentes, Billing APIs para facturación automatizada, y webhooks para sincronización en tiempo real. Imagina esto como un servicio de gimnasio: la suscripción es la membresía mensual, las facturas son los recibos que envías cada mes, y los webhooks son las notificaciones automáticas cuando alguien se da de baja o cambia de plan.

La arquitectura debe ser resiliente: los webhooks garantizan que tu base de datos refleje siempre el estado real en Stripe, evitando discrepancias. Un error común es tratar Stripe solo como pasarela de pago, cuando en realidad es un sistema de gestión de relaciones con clientes (CRM) financiero. La clave está en diseñar tu backend para manejar eventos asíncronos, no solo solicitudes síncronas.

Cómo funciona en la práctica

Veamos el flujo completo desde que un usuario se suscribe hasta su primer pago fallido:

  1. El cliente selecciona un plan en tu frontend y proporciona datos de pago.
  2. Tu backend crea un Customer en Stripe, luego una Subscription asociada a ese cliente.
  3. Stripe genera automáticamente la primera factura (Invoice) e intenta el pago.
  4. Si el pago es exitoso, Stripe envía un webhook invoice.paid a tu endpoint.
  5. Tu backend procesa el webhook, actualiza el estado del usuario en tu base de datos y envía acceso al servicio.
  6. Si el pago falla, Stripe envía invoice.payment_failed y tu sistema puede notificar al cliente o suspender el servicio temporalmente.

Código en acción

Creación de una suscripción con manejo de errores básico:

// Antes: Sin manejo de errores robusto
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

async function createSubscription(customerId, priceId) {
  const subscription = await stripe.subscriptions.create({
    customer: customerId,
    items: [{ price: priceId }],
    payment_behavior: 'default_incomplete',
    expand: ['latest_invoice.payment_intent']
  });
  return subscription;
}
// Después: Con validación y manejo de errores
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

async function createSubscription(customerId, priceId) {
  try {
    // Validar que el cliente existe
    const customer = await stripe.customers.retrieve(customerId);
    if (customer.deleted) {
      throw new Error('Cliente eliminado en Stripe');
    }
    
    // Crear suscripción con metadata para tracking
    const subscription = await stripe.subscriptions.create({
      customer: customerId,
      items: [{ price: priceId }],
      payment_behavior: 'default_incomplete',
      metadata: {
        internal_user_id: 'user_123',
        created_via: 'web_checkout'
      },
      expand: ['latest_invoice.payment_intent']
    });
    
    // Registrar en tu base de datos
    await db.subscriptions.create({
      stripe_subscription_id: subscription.id,
      status: subscription.status,
      current_period_end: new Date(subscription.current_period_end * 1000)
    });
    
    return {
      subscriptionId: subscription.id,
      clientSecret: subscription.latest_invoice.payment_intent.client_secret,
      status: subscription.status
    };
  } catch (error) {
    console.error('Error creando suscripción:', error);
    // Enviar a servicio de monitoreo
    await monitoring.logError('stripe_subscription_error', error);
    throw error;
  }
}

Errores comunes

  • No verificar firmas de webhooks: Cualquiera puede enviar peticiones a tu endpoint. Siempre valida la firma con stripe.webhooks.constructEvent().
  • Ignorar eventos duplicados: Stripe puede enviar el mismo webhook múltiples veces. Implementa idempotencia almacenando IDs de eventos procesados.
  • No manejar pagos fallidos: El 10-15% de los pagos recurrentes fallan mensualmente. Configura reintentos automáticos y notificaciones proactivas.
  • Depender solo del estado en tu base de datos: El estado real está en Stripe. Sincroniza regularmente o usa webhooks para mantener consistencia.
  • No probar flujos de cancelación: Los usuarios cancelarán. Asegúrate de manejar customer.subscription.deleted correctamente.

Checklist de dominio

  • ✓ Puedo crear un cliente, suscripción y factura en una sola transacción atómica
  • ✓ Mi endpoint de webhooks valida firmas y maneja eventos duplicados
  • ✓ Implementé lógica para pagos fallidos con reintentos configurados
  • ✓ Sé cómo actualizar/cancelar suscripciones mediante API
  • ✓ Uso metadata para asociar objetos de Stripe con mis registros internos
  • ✓ Configuré eventos esenciales: invoice.paid, invoice.payment_failed, customer.subscription.deleted
  • ✓ Probé el flujo completo con modos de prueba de Stripe

Implementar endpoint de webhooks con manejo de eventos críticos

Construye un endpoint de webhooks que procese 3 eventos esenciales y mantenga sincronizada tu base de datos. Sigue estos pasos:

  1. Crea una ruta POST /api/stripe/webhook en tu backend
  2. Implementa verificación de firma usando la clave secreta de webhooks de Stripe
  3. Procesa estos eventos:
    • invoice.paid: Actualiza el estado de la suscripción a activa y registra la fecha de pago
    • invoice.payment_failed: Marca la suscripción como "payment_failed" y notifica al usuario
    • customer.subscription.deleted: Cancela el acceso al servicio y archiva los datos
  4. Implementa idempotencia: almacena IDs de eventos procesados para evitar duplicados
  5. Agrega logging detallado para debugging en producción
  6. Prueba con la CLI de Stripe: stripe listen --forward-to localhost:3000/api/stripe/webhook
Pistas
  • Usa stripe.webhooks.constructEvent() para verificar la firma
  • Los eventos tienen propiedad 'type' y 'data.object' con los detalles
  • Guarda event.id en tu base de datos antes de procesar para idempotencia

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.