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:
- El cliente selecciona un plan en tu frontend y proporciona datos de pago.
- Tu backend crea un Customer en Stripe, luego una Subscription asociada a ese cliente.
- Stripe genera automáticamente la primera factura (Invoice) e intenta el pago.
- Si el pago es exitoso, Stripe envía un webhook
invoice.paida tu endpoint. - Tu backend procesa el webhook, actualiza el estado del usuario en tu base de datos y envía acceso al servicio.
- Si el pago falla, Stripe envía
invoice.payment_failedy 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.deletedcorrectamente.
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:
- Crea una ruta POST
/api/stripe/webhooken tu backend - Implementa verificación de firma usando la clave secreta de webhooks de Stripe
- 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
- Implementa idempotencia: almacena IDs de eventos procesados para evitar duplicados
- Agrega logging detallado para debugging en producción
- Prueba con la CLI de Stripe:
stripe listen --forward-to localhost:3000/api/stripe/webhook
- 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.