Quiz: Facturas y Billing APIs

Quiz
15 min~5 min lectura

Quiz Interactivo

Pon a prueba tus conocimientos

Concepto clave

Las facturas de Stripe son documentos que representan transacciones de pago entre tu negocio y tus clientes. A diferencia de los cargos simples, las facturas están diseñadas para sistemas de suscripción y billing recurrente. Piensa en ellas como recibos profesionales que se generan automáticamente cuando un cliente se suscribe, renueva o realiza un pago único.

Las Billing APIs son el conjunto de herramientas que Stripe proporciona para gestionar todo el ciclo de facturación: desde crear suscripciones hasta enviar recordatorios de pago. La magia está en cómo se integran con los webhooks, que son notificaciones en tiempo real que Stripe envía a tu servidor cuando ocurren eventos importantes, como un pago exitoso o una factura fallida.

Cómo funciona en la práctica

Imagina que tienes una plataforma SaaS con planes mensuales. Cuando un cliente elige un plan, creas una suscripción en Stripe. Stripe genera automáticamente una factura y la marca como "draft" (borrador). Al momento del pago, si es exitoso, la factura se marca como "paid" (pagada) y se envía un webhook a tu backend. Si falla, Stripe reintenta el pago y notifica a tu sistema para que puedas tomar acciones, como desactivar el acceso del cliente.

Paso a paso:

  1. Crear un producto y un precio en el Dashboard de Stripe o mediante API.
  2. Cuando un cliente se suscribe, usar la API para crear una suscripción asociada a ese precio.
  3. Stripe genera una factura inicial y la intenta cobrar inmediatamente.
  4. Tu backend recibe un webhook con el evento invoice.payment_succeeded o invoice.payment_failed.
  5. Basado en el webhook, actualizas el estado del usuario en tu base de datos (ej: activar o pausar su cuenta).

Código en acción

Crear una suscripción y manejar el webhook de factura pagada:

// Crear una suscripción en Stripe (Node.js con la librería stripe)
const stripe = require('stripe')('sk_test_...');

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 {
    subscriptionId: subscription.id,
    invoiceId: subscription.latest_invoice.id,
    clientSecret: subscription.latest_invoice.payment_intent.client_secret,
  };
}

Manejar el webhook de factura pagada:

# Ejemplo en Python con Flask
from flask import Flask, request, jsonify
import stripe

app = Flask(__name__)
stripe.api_key = 'sk_test_...'

@app.route('/webhook', methods=['POST'])
def webhook():
    payload = request.get_data(as_text=True)
    sig_header = request.headers.get('Stripe-Signature')
    
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, 'whsec_...'
        )
    except ValueError as e:
        return 'Invalid payload', 400
    except stripe.error.SignatureVerificationError as e:
        return 'Invalid signature', 400
    
    # Manejar el evento de factura pagada
    if event['type'] == 'invoice.payment_succeeded':
        invoice = event['data']['object']
        customer_id = invoice['customer']
        # Actualizar tu base de datos: activar acceso del usuario
        # Ej: update_user_access(customer_id, active=True)
        print(f'Factura {invoice["id"]} pagada para cliente {customer_id}')
    
    return jsonify({'status': 'success'}), 200

Errores comunes

  • No verificar la firma del webhook: Cualquiera puede enviar peticiones a tu endpoint /webhook. Siempre valida la firma con stripe.Webhook.construct_event para asegurar que viene de Stripe.
  • Confundir invoice.paid con invoice.payment_succeeded: invoice.paid se dispara cuando una factura se marca como pagada, pero invoice.payment_succeeded es más específico para pagos exitosos. Usa invoice.payment_succeeded para activar acceso de usuarios.
  • No manejar reintentos de pagos fallidos: Stripe reintenta pagos automáticamente, pero si fallan varias veces, la suscripción se cancela. Configura webhooks para invoice.payment_failed y notifica al cliente o pausa su cuenta.
  • Olvidar expandir objetos anidados: Al crear una suscripción, si necesitas el client_secret del payment intent, usa expand: ['latest_invoice.payment_intent']. De lo contrario, tendrás que hacer otra llamada a la API.

Checklist de dominio

  • Puedo crear una suscripción con la API de Stripe y manejar la factura inicial.
  • Sé configurar un endpoint de webhook y verificar la firma de Stripe.
  • Reconozco y manejo los eventos clave: invoice.payment_succeeded, invoice.payment_failed, customer.subscription.updated.
  • Entiendo la diferencia entre facturas en estado draft, open, paid, y void.
  • Puedo listar todas las facturas de un cliente y filtrar por estado.
  • Sé cómo enviar facturas por correo automáticamente desde el Dashboard o mediante API.
  • Puedo manejar casos edge: reembolsos, descuentos, y impuestos en facturas.

Implementa un sistema de webhooks para manejar facturas fallidas

En este ejercicio, crearás un endpoint de webhook que maneje facturas con pagos fallidos y notifique al usuario. Sigue estos pasos:

  1. Configura un servidor local con ngrok o despliega en un servicio como Heroku/Railway.
  2. Crea un endpoint /webhook que acepte peticiones POST.
  3. Implementa la verificación de la firma del webhook usando la librería de Stripe.
  4. Cuando recibas el evento invoice.payment_failed, extrae el ID del cliente y el ID de la factura.
  5. Simula el envío de una notificación al cliente (puede ser un log en consola o un email simulado).
  6. Opcional: Si la factura ha fallado más de 2 veces, simula la pausa de la cuenta del usuario.

Usa el siguiente código base para empezar:

from flask import Flask, request, jsonify
import stripe

app = Flask(__name__)
stripe.api_key = 'sk_test_...'  # Reemplaza con tu clave de prueba
webhook_secret = 'whsec_...'    # Reemplaza con tu secreto de webhook

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    # Tu código aquí
    pass

if __name__ == '__main__':
    app.run(port=4242)
Pistas
  • Recuerda que el payload del webhook viene en request.get_data(as_text=True).
  • Usa stripe.Webhook.construct_event para verificar la firma y parsear el evento.
  • El objeto invoice dentro del evento tiene campos como 'customer' y 'attempt_count'.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.