Crear una Suscripción con el API de Stripe

Lectura
20 min~5 min lectura

Concepto clave

Una suscripción en Stripe es un modelo de negocio donde los clientes pagan de forma recurrente por acceso continuo a un producto o servicio. Piensa en Netflix: pagas mensualmente para ver series ilimitadas. En Stripe, esto se implementa combinando tres elementos fundamentales: Customer (el cliente), Price (el precio del plan) y Subscription (la suscripción que vincula ambos).

La magia está en la automatización: una vez creada, Stripe se encarga de cobrar periódicamente, generar facturas y notificar cambios mediante webhooks. Esto libera al desarrollador de gestionar manualmente renovaciones, recordatorios o fallos de pago. Es como contratar un jardinero que viene cada semana sin que tengas que recordárselo; solo configuras la frecuencia y él actúa.

Cómo funciona en la práctica

Para crear una suscripción, sigue estos pasos en orden lógico:

  1. Configura el precio: Define un objeto Price en el Dashboard de Stripe o mediante API. Especifica monto, moneda e intervalo (mensual, anual).
  2. Crea o identifica al cliente: Necesitas un Customer, que puede existir o crearse al momento con su método de pago.
  3. Inicia la suscripción: Usa la API para crear una Subscription, pasando el customer y el price. Stripe realiza el primer pago inmediatamente.
  4. Gestiona eventos: Configura webhooks para escuchar eventos como payment_failed o subscription_updated, y actúa en tu backend.

Ejemplo real: una SaaS de gestión de proyectos ofrece un plan "Pro" a $29/mes. Al registrarse, el usuario introduce su tarjeta; tu backend crea un Customer con ese método, luego una Subscription al price "pro_monthly", y el usuario accede al servicio. Cada mes, Stripe cobra automáticamente y envía un invoice.

Código en acción

Aquí un ejemplo funcional en Node.js con la librería stripe. Asegúrate de tener instalado stripe (npm install stripe) y configurada tu clave secreta.

const stripe = require('stripe')('sk_test_tu_clave_secreta');

// Antes: crear un customer y un price por separado (ineficiente si se repite)
async function crearSuscripcionAntes(customerId, priceId) {
  // Lógica dispersa
  const subscription = await stripe.subscriptions.create({
    customer: customerId,
    items: [{ price: priceId }],
  });
  return subscription;
}

// Después: función optimizada que maneja todo en un flujo
export async function crearSuscripcion(email, paymentMethodId, priceId) {
  try {
    // 1. Crear customer con método de pago
    const customer = await stripe.customers.create({
      email: email,
      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 }],
      expand: ['latest_invoice.payment_intent'], // Trae datos adicionales
    });

    // 3. Retornar estado para el frontend
    return {
      status: subscription.status,
      clientSecret: subscription.latest_invoice.payment_intent.client_secret,
      subscriptionId: subscription.id,
    };
  } catch (error) {
    console.error('Error creando suscripción:', error);
    throw new Error('No se pudo crear la suscripción');
  }
}

// Uso práctico
// crearSuscripcion('[email protected]', 'pm_card_visa', 'price_abc123');

En Python, el enfoque es similar:

import stripe
stripe.api_key = "sk_test_tu_clave_secreta"

def crear_suscripcion(email, payment_method_id, price_id):
    # Crear cliente
    customer = stripe.Customer.create(
        email=email,
        payment_method=payment_method_id,
        invoice_settings={
            'default_payment_method': payment_method_id
        }
    )
    
    # Crear suscripción
    subscription = stripe.Subscription.create(
        customer=customer.id,
        items=[{'price': price_id}],
        expand=['latest_invoice.payment_intent']
    )
    
    return {
        'status': subscription.status,
        'client_secret': subscription.latest_invoice.payment_intent.client_secret,
        'subscription_id': subscription.id
    }

Errores comunes

  • No expandir invoice.payment_intent: Si no usas expand, perderás el client_secret necesario para confirmar pagos en el frontend. Siempre incluye expand: ['latest_invoice.payment_intent'] para flujos de 3D Secure.
  • Olvidar configurar default_payment_method: Al crear un Customer, debes establecer invoice_settings.default_payment_method con el payment_method_id. Sin esto, los cobros recurrentes pueden fallar.
  • Manejo inadecuado de webhooks: No verificar firmas de webhooks permite ataques. Usa stripe.webhooks.constructEvent en Node.js o similar en otros lenguajes para autenticar eventos.
  • Ignorar estados de suscripción: Stripe devuelve status como active, past_due, o canceled. No asumas que active significa pago exitoso; verifica latest_invoice.paid.
  • Precios no recurrentes: Asegúrate de que el Price tenga recurring definido. Un price de una sola vez no funciona en suscripciones.

Checklist de dominio

  1. Puedo crear un Price recurrente via API o Dashboard y explicar sus parámetros (interval, amount).
  2. Sé crear un Customer con un método de pago y configurar default_payment_method para facturas.
  3. Implemento una función que crea una Subscription, maneja errores y retorna datos para el frontend.
  4. Configuro webhooks para escuchar invoice.payment_failed y actualizar el estado del usuario en mi base de datos.
  5. Verifico el estado de una suscripción (status, current_period_end) y sé cancelarla o pausarla mediante API.
  6. Comprendo la diferencia entre trial_period_days (prueba gratis) y billing_cycle_anchor (control de fechas de cobro).
  7. Uso expand para acceder a datos anidados como payment_intent sin hacer llamadas adicionales.

Implementa un endpoint de suscripción con manejo de errores

En este ejercicio, crearás un endpoint de backend que permita suscribir usuarios a un plan. Usarás Node.js o Python, y simularás un entorno real con Stripe en modo test.

  1. Prepara tu entorno: Instala la librería Stripe (npm install stripe o pip install stripe) y configura tu clave secreta de test (encuéntrala en el Dashboard de Stripe).
  2. Crea un Price de prueba: Ve al Dashboard de Stripe > Products > Add Product. Crea un producto "Plan Básico" con un Price recurrente mensual de $10. Anota el price_id (ej: price_abc123).
  3. Desarrolla el endpoint: En tu código, crea una función o ruta (ej: POST /api/subscribe) que:
    • Acepte email, paymentMethodId (simulado con pm_card_visa) y priceId.
    • Cree un Customer con el email y paymentMethodId, configurando default_payment_method.
    • Cree una Subscription usando ese customer y priceId, expandiendo latest_invoice.payment_intent.
    • Maneje errores con try-catch: si falla, retorna un mensaje claro (ej: "Pago rechazado").
    • Retorne un JSON con status, subscriptionId, y clientSecret.
  4. Prueba el flujo: Usa cURL o Postman para enviar una petición a tu endpoint con datos de prueba. Verifica que la suscripción aparezca en el Dashboard de Stripe como active.
  5. Agrega validación: Añade una validación básica (ej: verificar que el email tenga formato válido) antes de llamar a Stripe.
Pistas
  • Usa pm_card_visa como paymentMethodId para pruebas; es una tarjeta de prueba que siempre funciona.
  • Recuerda que expand es un array: ['latest_invoice.payment_intent']. Sin esto, client_secret será undefined.
  • En el Dashboard de Stripe, ve a Developers > Webhooks para ver eventos en tiempo real y depurar.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.