Concepto clave
La configuración de métodos de pago y facturación automática en Stripe es el motor financiero que mantiene tu negocio de suscripciones funcionando sin intervención manual. Imagina esto como un sistema de suscripción a un gimnasio: el cliente proporciona su tarjeta una vez, y cada mes se le cobra automáticamente mientras mantenga su membresía activa. Stripe actúa como el cajero automatizado que procesa esos pagos y genera recibos.
En términos técnicos, esto involucra tres componentes principales: PaymentMethods (tarjetas, bancos digitales), Subscriptions (planes recurrentes) y Invoices (facturas generadas automáticamente). La magia ocurre cuando Stripe combina estos elementos: cuando una suscripción se renueva, Stripe crea una factura, intenta cobrar usando el método de pago guardado, y si tiene éxito, marca la factura como pagada y envía un recibo.
Cómo funciona en la práctica
Vamos a seguir el flujo completo de un cliente que se suscribe a tu servicio:
- El cliente ingresa su información de pago en tu frontend (usando Stripe Elements o Checkout)
- Tu backend recibe un PaymentMethod ID seguro de Stripe
- Creas un Customer en Stripe y adjuntas el PaymentMethod
- Creas una Subscription para ese cliente con un plan específico
- Stripe genera automáticamente la primera factura y la paga
- Cada ciclo de facturación, Stripe repite el proceso: genera factura → intenta pago → envía webhook
El punto crítico aquí es que una vez configurado, el sistema funciona automáticamente. Tu única responsibilidad es manejar los fallos de pago a través de webhooks.
Código en acción
Primero, veamos cómo crear un cliente con método de pago y suscripción:
// Configuración inicial con Stripe Node.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
async function createSubscription(customerEmail, paymentMethodId, priceId) {
// 1. Crear cliente
const customer = await stripe.customers.create({
email: customerEmail,
payment_method: paymentMethodId,
invoice_settings: {
default_payment_method: paymentMethodId
}
});
// 2. Crear suscripción
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{
price: priceId
}],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent']
});
return {
clientSecret: subscription.latest_invoice.payment_intent.client_secret,
subscriptionId: subscription.id
};
}Ahora, veamos cómo manejar la renovación automática con webhooks:
// Webhook handler para invoice.payment_succeeded
app.post('/webhook', 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}`);
}
// Manejar el evento de factura pagada
if (event.type === 'invoice.payment_succeeded') {
const invoice = event.data.object;
// Aquí actualizas tu base de datos
await updateUserSubscription(invoice.customer, {
status: 'active',
current_period_end: new Date(invoice.period_end * 1000),
invoiceUrl: invoice.hosted_invoice_url
});
// Opcional: enviar email de confirmación
await sendInvoiceEmail(invoice.customer_email, invoice.hosted_invoice_url);
}
res.json({received: true});
});Errores comunes
- No configurar payment_behavior correctamente: Si usas 'default_incomplete' en suscripciones, asegúrate de confirmar el PaymentIntent en el frontend. La alternativa 'allow_incomplete' maneja esto automáticamente pero requiere lógica de reintento.
- Olvidar los webhooks en producción: Los eventos como invoice.payment_succeeded solo llegan vía webhooks. Sin ellos, tu base de datos no se actualiza tras pagos automáticos.
- No manejar fallos de pago: Stripe intentará cobrar varias veces, pero necesitas escuchar invoice.payment_failed para notificar al usuario o degradar su servicio.
- Usar precios en lugar de productos: Los precios definen el costo y ciclo, pero los productos definen qué estás vendiendo. Crea productos primero, luego precios asociados.
- Ignorar el campo default_payment_method: Sin esto, las facturas futuras no sabrán qué método de pago usar. Siempre configúralo al crear el cliente.
Checklist de dominio
- Puedo crear un cliente con método de pago por defecto configurado
- Sé diferenciar entre PaymentMethod, PaymentIntent y SetupIntent
- He implementado webhooks para invoice.payment_succeeded y invoice.payment_failed
- Puedo listar todas las suscripciones de un cliente y su estado actual
- Entiendo cómo Stripe reintenta pagos fallidos automáticamente
- Sé dó encontrar las facturas generadas automáticamente en el Dashboard
- Puedo actualizar/cancelar una suscripción y predecir su próxima factura
Implementa un sistema completo de suscripción con renovación automática
En este ejercicio, crearás un endpoint backend que maneje suscripciones recurrentes con facturación automática.
- Crea un endpoint POST /api/subscribe que reciba:
- email del cliente
- paymentMethodId (simulado o real desde Stripe.js)
- priceId (usa 'price_1' para mensual o 'price_2' para anual)
- Implementa la lógica para:
- Crear un cliente en Stripe con el método de pago como predeterminado
- Crear una suscripción que se renueve automáticamente
- Devolver el clientSecret para confirmar el pago inicial
- Crea un webhook handler en /webhook que:
- Verifique la firma de Stripe
- Actualice tu base de datos (simulada) cuando una factura se pague exitosamente
- Envie un email simulado (console.log) con el enlace a la factura
- Prueba el flujo completo:
- Suscribe un cliente
- Simula un webhook de invoice.payment_succeeded usando stripe CLI
- Verifica que tu base de datos se actualizó
Requisitos técnicos: Usa Node.js con Express, el SDK de Stripe, y variables de entorno para las claves.
Pistas- Recuerda que el payment_behavior: 'default_incomplete' requiere confirmación del PaymentIntent en el frontend
- Usa stripe.webhooks.constructEvent() para verificar webhooks, no confíes en el body crudo
- Para pruebas, genera eventos con 'stripe trigger invoice.payment_succeeded' en la CLI
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.