# Integración de Pagos **Versión:** 1.0.0 **Origen:** projects/trading-platform **Estado:** Producción **Última actualización:** 2025-12-08 --- ## Descripción Sistema completo de pagos con integración Stripe: - Gestión de clientes en Stripe - Checkout sessions para pagos seguros - Suscripciones con ciclos de facturación - Métodos de pago (tarjetas) - Billing portal de autoservicio - Webhooks para eventos de Stripe - Wallet interno para balance de usuario - Códigos promocionales --- ## Características | Característica | Descripción | |----------------|-------------| | Stripe Checkout | Hosted checkout pages | | Suscripciones | Monthly/yearly con trial | | Payment Intents | One-time payments | | Billing Portal | Self-service portal | | Webhooks | Eventos en tiempo real | | Wallet | Balance interno | | Promo codes | Descuentos y cupones | | Invoices | Facturas automáticas | | Refunds | Reembolsos parciales/totales | --- ## Stack Tecnológico ```yaml backend: framework: NestJS / Express payment_processor: Stripe database: PostgreSQL packages: - "stripe" ``` --- ## Dependencias NPM ```json { "stripe": "^14.x" } ``` --- ## Tablas Requeridas | Tabla | Propósito | |-------|-----------| | financial.stripe_customers | Relación user-customer Stripe | | financial.subscription_plans | Planes disponibles | | financial.subscriptions | Suscripciones activas | | financial.payments | Historial de pagos | | financial.invoices | Facturas | | financial.wallets | Balance del usuario | | financial.wallet_transactions | Movimientos del wallet | | financial.promo_codes | Códigos promocionales | --- ## Estructura del Módulo ``` payments/ ├── services/ │ ├── stripe.service.ts # Integración con Stripe API │ ├── subscription.service.ts # Gestión de suscripciones │ └── wallet.service.ts # Wallet interno ├── controllers/ │ └── payments.controller.ts # Endpoints REST ├── webhooks/ │ └── stripe.webhook.ts # Handler de webhooks ├── types/ │ └── payments.types.ts # Tipos e interfaces └── dto/ ├── create-checkout.dto.ts └── subscription.dto.ts ``` --- ## Modelos de Datos ### StripeCustomer ```typescript interface StripeCustomer { id: string; userId: string; stripeCustomerId: string; // cus_xxx email?: string; defaultPaymentMethodId?: string; // pm_xxx metadata?: Record; createdAt: Date; updatedAt: Date; } ``` ### SubscriptionPlan ```typescript interface SubscriptionPlan { id: string; name: string; // "Pro Plan" slug: string; // "pro" description?: string; priceMonthly: number; // 29.99 priceYearly?: number; // 299.99 currency: string; // "usd" stripePriceIdMonthly?: string; // price_xxx stripePriceIdYearly?: string; // price_xxx stripeProductId?: string; // prod_xxx features: PlanFeature[]; isActive: boolean; sortOrder: number; } ``` ### Subscription ```typescript interface Subscription { id: string; userId: string; planId: string; stripeSubscriptionId?: string; // sub_xxx stripeCustomerId?: string; // cus_xxx status: 'trialing' | 'active' | 'past_due' | 'cancelled' | 'unpaid'; billingCycle: 'monthly' | 'yearly'; currentPeriodStart?: Date; currentPeriodEnd?: Date; trialStart?: Date; trialEnd?: Date; cancelAtPeriodEnd: boolean; cancelledAt?: Date; cancellationReason?: string; currentPrice?: number; currency: string; } ``` ### Wallet ```typescript interface Wallet { id: string; userId: string; currency: string; balance: number; availableBalance: number; pendingBalance: number; isActive: boolean; dailyWithdrawalLimit: number; monthlyWithdrawalLimit: number; } ``` --- ## Flujo de Pago con Stripe Checkout ``` 1. Usuario selecciona plan │ ▼ 2. Backend crea Checkout Session - Obtiene/crea customer en Stripe - Configura line_items con price_id - Define success_url y cancel_url │ ▼ 3. Redirect a Stripe Checkout │ ▼ 4. Usuario completa pago │ ▼ 5. Stripe envía webhook - checkout.session.completed - invoice.paid │ ▼ 6. Backend procesa webhook - Crea/actualiza suscripción - Registra pago - Activa features del plan ``` --- ## Uso Rápido ### 1. Crear cliente en Stripe ```typescript const customer = await stripeService.getOrCreateCustomer( userId, userEmail ); // { stripeCustomerId: 'cus_xxx', ... } ``` ### 2. Crear checkout session ```typescript const session = await stripeService.createCheckoutSession({ userId: 'user-uuid', planId: 'plan-uuid', billingCycle: 'monthly', successUrl: 'https://app.com/success?session_id={CHECKOUT_SESSION_ID}', cancelUrl: 'https://app.com/pricing', promoCode: 'SUMMER20', // opcional }); // Redirect usuario a session.url ``` ### 3. Verificar suscripción ```typescript const subscription = await subscriptionService.getSubscriptionByUserId(userId); if (subscription?.status === 'active') { // Usuario tiene suscripción activa const hasFeature = subscription.plan.apiAccess; } ``` ### 4. Billing Portal (autoservicio) ```typescript const portal = await stripeService.createBillingPortalSession( userId, 'https://app.com/dashboard' ); // Redirect a portal.url // Usuario puede: actualizar tarjeta, ver facturas, cancelar ``` ### 5. Cancelar suscripción ```typescript // Al final del período await subscriptionService.cancelSubscription(userId, false, 'User requested'); // Inmediatamente await subscriptionService.cancelSubscription(userId, true); ``` ### 6. Cambiar de plan ```typescript await subscriptionService.changePlan(userId, newPlanId, 'yearly'); ``` --- ## Webhook Handler ```typescript // POST /webhooks/stripe async handleStripeWebhook(req: Request) { const signature = req.headers['stripe-signature']; const event = stripe.webhooks.constructEvent( req.body, signature, process.env.STRIPE_WEBHOOK_SECRET ); switch (event.type) { case 'checkout.session.completed': await this.handleCheckoutCompleted(event.data.object); break; case 'invoice.paid': await this.handleInvoicePaid(event.data.object); break; case 'invoice.payment_failed': await this.handlePaymentFailed(event.data.object); break; case 'customer.subscription.updated': await this.handleSubscriptionUpdated(event.data.object); break; case 'customer.subscription.deleted': await this.handleSubscriptionDeleted(event.data.object); break; } return { received: true }; } private async handleCheckoutCompleted(session: Stripe.Checkout.Session) { const { userId, planId, billingCycle } = session.metadata!; // Crear suscripción local await db.query(` INSERT INTO financial.subscriptions ( user_id, plan_id, stripe_subscription_id, stripe_customer_id, status, billing_cycle, current_period_start, current_period_end ) VALUES ($1, $2, $3, $4, 'active', $5, $6, $7) `, [userId, planId, session.subscription, session.customer, billingCycle, ...]); } ``` --- ## Variables de Entorno ```env # Stripe STRIPE_SECRET_KEY=sk_live_xxx # o sk_test_xxx STRIPE_PUBLISHABLE_KEY=pk_live_xxx # para frontend STRIPE_WEBHOOK_SECRET=whsec_xxx # URLs FRONTEND_URL=https://app.example.com STRIPE_SUCCESS_URL=${FRONTEND_URL}/success STRIPE_CANCEL_URL=${FRONTEND_URL}/pricing ``` --- ## Endpoints Principales | Método | Ruta | Descripción | |--------|------|-------------| | GET | /plans | Listar planes disponibles | | GET | /plans/:id | Obtener plan por ID | | GET | /subscription | Obtener suscripción del usuario | | POST | /checkout/subscription | Crear checkout para suscripción | | POST | /checkout/course | Crear checkout para curso | | GET | /billing-portal | Obtener URL del billing portal | | POST | /subscription/cancel | Cancelar suscripción | | POST | /subscription/resume | Reactivar suscripción | | POST | /subscription/change-plan | Cambiar de plan | | GET | /invoices | Listar facturas del usuario | | GET | /payment-methods | Listar métodos de pago | | POST | /payment-methods | Agregar método de pago | | DELETE | /payment-methods/:id | Eliminar método de pago | | POST | /webhooks/stripe | Webhook handler | --- ## Configuración en Stripe Dashboard ### 1. Productos y Precios ``` Producto: Pro Plan (prod_xxx) ├── Precio mensual: $29.99/month (price_monthly_xxx) └── Precio anual: $299.99/year (price_yearly_xxx) ``` ### 2. Webhook Endpoints ``` Endpoint: https://api.example.com/webhooks/stripe Events: - checkout.session.completed - invoice.paid - invoice.payment_failed - customer.subscription.updated - customer.subscription.deleted - customer.subscription.created ``` ### 3. Customer Portal Configurar en Settings > Billing > Customer portal: - Allow customers to update payment methods - Allow customers to view invoice history - Allow customers to cancel subscriptions --- ## Wallet (Balance Interno) ### Depositar fondos ```typescript await walletService.deposit({ userId: 'user-uuid', amount: 100.00, currency: 'usd', description: 'Initial deposit', }); ``` ### Usar balance para pago ```typescript const canPay = await walletService.canAfford(userId, 50.00); if (canPay) { await walletService.debit(userId, 50.00, 'Course purchase'); } ``` ### Reembolso al wallet ```typescript await walletService.credit(userId, 25.00, 'Partial refund'); ``` --- ## Códigos Promocionales ```typescript // Validar código const result = await promoService.validateCode('SUMMER20', { userId, planId, amount: 29.99, }); if (result.valid) { // Aplicar descuento const finalPrice = 29.99 - result.discountAmount; } ``` --- ## Adaptaciones Necesarias 1. **Productos en Stripe**: Crear productos y precios en dashboard 2. **Webhook URL**: Configurar endpoint público 3. **Planes**: Ajustar features según tu modelo de negocio 4. **Moneda**: Configurar currency (usd, eur, mxn, etc.) 5. **Trial**: Configurar período de prueba si aplica 6. **Tax**: Configurar impuestos si aplica (Stripe Tax) --- ## Referencias - [Stripe API Reference](https://stripe.com/docs/api) - [Stripe Checkout](https://stripe.com/docs/payments/checkout) - [Stripe Subscriptions](https://stripe.com/docs/billing/subscriptions) - [Stripe Webhooks](https://stripe.com/docs/webhooks) - [Stripe Customer Portal](https://stripe.com/docs/billing/subscriptions/customer-portal) --- **Mantenido por:** Sistema NEXUS **Proyecto origen:** Trading Platform