Stripe — Suscripciones en Plataforma Web
Finnova usa Stripe como procesador de pagos para la gestión de suscripciones de la plataforma web. Stripe asume la responsabilidad de cumplimiento PCI-DSS en el procesamiento de tarjetas, lo que reduce significativamente la superficie de riesgo en nuestra infraestructura (ver Compliance y Privacidad).
Casos de uso
1. Alta de suscripción
Cuando un usuario nuevo elige un plan de pago:
- Se crea un Customer en Stripe asociado a su cuenta Finnova.
- El usuario introduce sus datos de tarjeta directamente en Stripe Elements (nunca pasan por nuestros servidores).
- Se crea una Subscription en Stripe vinculada al plan (
Price) correspondiente. - El webhook
customer.subscription.createdactiva el acceso a funcionalidades premium en nuestra base de datos.
2. Renovación automática
Las suscripciones se renuevan automáticamente según el ciclo del plan (mensual / anual):
- Stripe intenta el cobro al inicio del nuevo período.
- El webhook
invoice.payment_succeededconfirma la renovación y extiende el acceso. - Si el cobro falla,
invoice.payment_failedactiva el flujo de dunning (reintentos automáticos de Stripe) y se notifica al usuario por email.
3. Cambio de plan (upgrade / downgrade)
- Se llama a
stripe.subscriptions.update()con el nuevoPrice. - Stripe calcula el prorrateo automáticamente.
- El webhook
customer.subscription.updatedsincroniza el plan activo en nuestra BD.
4. Cancelación
- El usuario puede cancelar desde la app en cualquier momento.
- Se llama a
stripe.subscriptions.update({ cancel_at_period_end: true })para no interrumpir el acceso hasta fin del período ya pagado. - El webhook
customer.subscription.deletedrevoca el acceso premium cuando vence.
5. Actualización de método de pago
- El usuario accede al Customer Portal de Stripe (hosted page) para actualizar su tarjeta sin que nosotros manejemos los datos.
- Se genera la sesión con
stripe.billingPortal.sessions.create()y se redirige al usuario.
Planes definidos
| Plan | Ciclo | Descripción |
|---|---|---|
| Free | — | Acceso básico sin costo |
| Pro Mensual | Mensual | Acceso completo; renovación cada mes |
| Pro Anual | Anual | Acceso completo; precio reducido vs. mensual |
Los Price IDs de Stripe se almacenan como variables de entorno y nunca se hardcodean en el código.
Integración
Flujo general
Frontend
- Usar Stripe.js + Stripe Elements para el formulario de tarjeta.
- Nunca manejar números de tarjeta en nuestro código.
- Confirmar el pago con
stripe.confirmPayment()ostripe.confirmCardSetup()para 3D Secure si aplica.
Backend
- SDK oficial de Stripe para Node.js (
stripenpm package). - Crear un
Customerla primera vez que un usuario inicia una suscripción de pago y persistir elstripe_customer_iden la tabla de usuarios. - Todos los endpoints de pagos requieren autenticación previa del usuario.
- La clave secreta de Stripe (
STRIPE_SECRET_KEY) solo vive en variables de entorno del servidor — nunca en el cliente.
Webhooks
Registrar un único endpoint en el backend (p. ej. POST /webhooks/stripe) que reciba y valide todos los eventos con la Webhook Signing Secret.
Eventos a manejar:
| Evento | Acción en nuestra BD |
|---|---|
customer.subscription.created | Activar plan premium |
customer.subscription.updated | Actualizar plan activo |
customer.subscription.deleted | Revocar acceso premium |
invoice.payment_succeeded | Registrar pago exitoso |
invoice.payment_failed | Marcar suscripción en gracia / notificar usuario |
Validación: siempre verificar la firma del webhook con stripe.webhooks.constructEvent() antes de procesar cualquier payload.
Variables de entorno requeridas
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_PRO_MONTHLY=price_...
STRIPE_PRICE_PRO_ANNUAL=price_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY es la única variable que puede exponerse al cliente.
Consideraciones de seguridad
- PCI-DSS: Stripe maneja el procesamiento de tarjetas. Nuestro scope queda reducido a SAQ A (el más simple).
- Idempotency keys: usar en todas las llamadas de creación a la API de Stripe para evitar cargos duplicados ante reintentos.
- Modo test: usar claves
sk_test_/pk_test_en desarrollo y staging; nunca mezclar con producción. - Logs: no registrar en logs ni almacenar números de tarjeta, CVV ni datos de autenticación de pago.