Práctico

Configuración de Stripe

Usa Stripe Checkout para pagos y finaliza vía webhooks para otorgar créditos. Configura variables de entorno, crea sesiones, maneja callbacks y procesa eventos firmados.

Visión general

Este template usa Stripe Checkout para pagos y un libro de créditos para otorgar saldo tras la compra.

  • UI: /[locale]/pricing muestra planes desde un archivo TypeScript tipado.
  • Crear sesión: el cliente llama a POST /api/checkout y se redirige a Stripe.
  • Volver al sitio: Stripe redirige al usuario a /api/pay/callback/stripe (GET).
  • Finalizar en servidor: Stripe envía un webhook a /api/pay/webhook/stripe (POST). El webhook marca el pedido como pagado y otorga créditos.

El webhook es la fuente de verdad; el callback solo navega al usuario tras el pago.


Recursos de inicio rápido


Pasarelas de pago 101

¿Qué es una pasarela de pago?

Una pasarela de pago es una herramienta digital que los negocios online usan para procesar y autorizar pagos electrónicos (tarjetas, wallets, transferencias). Es el equivalente online del lector físico de tarjetas. Actúa como intermediaria que valida, aprueba o rechaza transacciones de forma segura por internet.

Casi 7,4 billones de USD en ventas de ecommerce se proyectan para 2025. Integrar una pasarela es clave para ofrecer una experiencia de pago fluida, mejorar la conversión y reforzar la seguridad y la confianza del cliente.

Cómo funcionan las pasarelas de pago

  1. Compra del cliente: introduce los datos de pago en tu checkout.
  2. Cifrado y envío: el sitio cifra y envía los datos a la pasarela.
  3. Reenvío de la transacción: la pasarela reenvía la info al procesador.
  4. Comunicación con el emisor: el procesador envía los detalles al banco emisor.
  5. Aprobación o rechazo: el banco decide según fondos y reglas de seguridad.
  6. Respuesta de vuelta: la decisión vuelve al procesador y a la pasarela.
  7. Finalización: si se aprueba, el cliente ve confirmación; si no, se informa el rechazo.
  8. Liquidación: las operaciones aprobadas se liquidan en tu banco adquirente y luego en tu cuenta.

Aun con varios pasos, todo ocurre de forma automática en segundos.

Cómo integrar una pasarela de pago

  1. Elige un proveedor: comisiones, métodos admitidos, seguridad y compatibilidad.
  2. Cuenta de comercio: algunos (p. ej., Stripe) la integran; otros requieren una aparte.
  3. Obtén las claves API: autentican tu web/app con la pasarela.
  4. Integra la pasarela: plugins (Shopify/WooCommerce) o código. Las APIs de Stripe son muy developer‑friendly.
  5. Prueba en sandbox: valida flujos con entornos y tarjetas de prueba.
  6. Pasa a producción: usa claves live y monitoriza.

Endpoints

  • /api/checkout (POST): valida el plan en src/data/pricing.ts, crea la sesión y guarda un order con estado created.
  • /api/pay/callback/stripe (GET): usado por la redirección de Stripe; ahora solo redirige a éxito/fracaso.
  • /api/pay/webhook/stripe (POST): verifica la firma y maneja checkout.session.completed para marcar pagado y otorgar créditos.

Flujo de créditos

  1. Buscamos order_no en los metadatos de la sesión.
  2. Actualizamos el pedido a paid y guardamos detalles del pago.
  3. Insertamos una fila positiva en credits (trans_type: order_pay). El balance es la suma de abonos no vencidos menos todos los consumos.

Requisitos

Variables en .env.local:

STRIPE_PRIVATE_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_WEB_URL=http://localhost:3000
NEXT_PUBLIC_PAY_CANCEL_URL=/pricing
NEXT_PUBLIC_PAY_SUCCESS_URL=/pricing
NEXT_PUBLIC_PAY_FAIL_URL=/pricing

src/integrations/stripe.ts usa STRIPE_SECRET_KEY.


Webhook local

stripe login
stripe listen --forward-to localhost:3000/api/pay/webhook/stripe
# Copia el whsec en STRIPE_WEBHOOK_SECRET
stripe trigger checkout_session_completed

Nota: payment_intent.succeeded no se maneja por defecto. Usa el evento checkout_session_completed.


Prueba rápida

  1. Regístrate/inicia sesión.
  2. Ve a /[locale]/pricing y elige un plan.
  3. Completa el pago con 4242 4242 4242 4242.
  4. Stripe redirige al callback; el webhook confirma y otorga créditos.
  5. Verifica en /[locale]/credits-test o POST /api/account/credits.

Guía de integración de Stripe (resumen)

Integrar Stripe en tu sitio web es directo si sigues estos pasos:

  1. Crea una cuenta en Stripe: registra tu negocio y método de cobro.
  2. Obtén las claves API: en Dashboard → Developers (publicable y secreta).
  3. Instala las librerías: SDK oficial de Stripe para tu lenguaje (JS/TS, Ruby, Python, etc.).
  4. Frontend: usa Stripe.js y componentes (Elements/Payment Element) o plugins para capturar datos de tarjeta de forma segura.
  5. Backend: inicializa Stripe con tu clave secreta y expón endpoints para PaymentIntents o Checkout Sessions.
  6. Recopila datos de pago: evita manejar tarjetas en tu servidor usando los componentes de Stripe.
  7. Envía al servidor: transmite la intención de pago por HTTPS de forma segura.
  8. Procesa en servidor: crea PaymentIntents o Checkout Sessions con el SDK.
  9. Gestiona la respuesta: actualiza tu base de datos e informa al cliente.
  10. Errores y bordes: fondos insuficientes, tarjetas vencidas, 3DS, reintentos.
  11. Prueba a fondo: modo de pruebas, webhooks y tarjetas de test.
  12. Lanza a producción: cambia a claves live, habilita métodos y monitoriza.

Consejo: empieza por la guía oficial — https://docs.stripe.com/get-started


Detalles

  • Planes en src/data/pricing.ts (tipados y compartidos).
  • handleCheckoutSession soporta pagos únicos y suscripciones (busca el PaymentIntent en la factura más reciente para suscripciones).

Productos vs Precios (Stripe)

Stripe separa el catálogo de “lo que vendes” de “cómo se cobra”:

  • Producto (prod_...): nombre/descr., metadatos de catálogo; un producto puede tener muchos precios.
  • Precio (price_...): moneda, importe, intervalo recurrente (mes/año), pruebas, impuestos, niveles. Las suscripciones se adjuntan a un Precio.

Por qué usamos IDs de Precio en Checkout

  • Las suscripciones necesitan términos comerciales exactos. Adjuntar a price_... habilita renovaciones correctas, prorrateo, pruebas y Stripe Tax.
  • Las renovaciones referencian el mismo price_... en las líneas de factura, lo que permite al webhook mapear el plan y otorgar créditos cada ciclo.
  • Operativamente más seguro que precios “ad‑hoc”: gestionas importes y reglas en Stripe, el código permanece estable.

Dónde encontrar los IDs de Precio en Stripe

  1. Panel → Productos → elige el producto.
  2. En la tabla de Precios, haz clic en los 3 puntos al final de la fila → “Copiar ID de precio”.
  3. Empieza con price_... — no lo confundas con el ID de producto (prod_...).

Variables de entorno (opcional, recomendado)

# Asocia tus planes a Precios de Stripe; si está vacío, se usa price_data inline
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_MONTHLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_MONTHLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_YEARLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_YEARLY=price_...
# Variantes en CNY (opcional)
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_MONTHLY_CNY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_MONTHLY_CNY=price_...
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_YEARLY_CNY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_YEARLY_CNY=price_...

Comportamiento con/sin IDs de Precio

  • Si un plan de suscripción tiene Price ID, Checkout lo usa directamente.
  • Si no, Checkout crea la sesión con price_data inline usando los importes de src/data/pricing.ts (fallback seguro).

Renovaciones y Créditos

El template maneja las renovaciones automáticamente:

  • Webhook invoice.payment_succeeded (con billing_reason=subscription_cycle) crea un pedido de renovación y otorga créditos del plan para el periodo.
  • Idempotencia: se omite si ya existe un pedido para (subscription_id, period_start).
  • La compra inicial sigue checkout.session.completed; para evitar doble crédito, se ignoran facturas que no sean de ciclo.

Recordatorio: reenvía los webhooks durante las pruebas

En entorno local (o cualquier URL no productiva), asegúrate de que Stripe reenvía los eventos a tu backend; de lo contrario, el pago se completa pero el pedido/créditos no se finalizan:

stripe listen --forward-to localhost:3000/api/pay/webhook/stripe

Si usas un dominio remoto o túnel, reenvía a esa URL en lugar de localhost.


Facturación y Suscripciones

Portal del Cliente

Activa el Customer Portal de Stripe y personaliza qué puede gestionar el usuario (cancelar/reanudar, actualizar tarjeta, ver facturas).

Incluido en este template:

  • API: GET /api/billing/portal — crea una sesión de portal y redirige a Stripe
  • UI: /:locale/account/billing — botón “Manage billing” que abre el portal

Implementación:

  • Ruta API: src/app/api/billing/portal/route.ts
    • Busca o crea un Customer de Stripe por el email del usuario autenticado
    • Crea una sesión de portal con return_url a /:locale/account/billing

Uso en la interfaz (Server Component):

  • src/app/[locale]/account/billing/page.tsx enlaza a /api/billing/portal?locale=<locale>

Cobros fallidos (Dunning)

Webhook: invoice.payment_failed envía un email para actualizar el método de pago mediante Resend.

  • Plantilla: src/services/email/templates/payment-failed.tsx
  • Envío: sendPaymentFailedEmail() en src/services/email/send.ts
  • Webhook: ver src/app/api/pay/webhook/stripe/route.ts

Prueba local con Stripe CLI:

stripe trigger invoice_payment_failed

Nota: El email incluye enlace a /:locale/account/billing para abrir el portal.


Otras opciones de pago

Stripe es solo una opción. Si necesitas alternativas como pagos con criptomonedas o PayPal, contáctame y te ayudo a elegir e integrar el proveedor adecuado para tu stack y mercado.