--- id: "ET-PAY-004" title: "API REST Payments" type: "Technical Specification" status: "Done" priority: "Alta" epic: "OQI-005" project: "trading-platform" version: "1.0.0" created_date: "2025-12-05" updated_date: "2026-01-04" --- # ET-PAY-004: API REST Payments **Epic:** OQI-005 Pagos y Stripe **Versión:** 1.0 **Fecha:** 2025-12-05 --- ## 1. Endpoints Payments ### POST `/api/v1/payments/intent` Crea Payment Intent para pago one-time **Request:** ```json { "amount": 99.99, "payment_method_id": "pm_...", "description": "Premium course purchase" } ``` **Response 200:** ```json { "success": true, "data": { "payment_intent_id": "pi_...", "client_secret": "pi_..._secret_...", "status": "requires_confirmation" } } ``` --- ### GET `/api/v1/payments` Lista pagos del usuario **Response 200:** ```json { "success": true, "data": { "payments": [ { "id": "uuid", "amount": 99.99, "status": "succeeded", "description": "Premium course", "created_at": "2025-01-20T10:00:00Z" } ] } } ``` --- ### POST `/api/v1/payments/:id/refund` Solicita reembolso (admin) **Request:** ```json { "reason": "requested_by_customer", "amount": 99.99 } ``` --- ## 2. Endpoints Subscriptions ### POST `/api/v1/subscriptions` Crea suscripción **Request:** ```json { "price_id": "price_...", "payment_method_id": "pm_..." } ``` --- ### GET `/api/v1/subscriptions` Lista suscripciones activas --- ### DELETE `/api/v1/subscriptions/:id` Cancela suscripción **Query:** `?immediate=false` --- ## 3. Endpoints Payment Methods ### POST `/api/v1/payment-methods` Guarda método de pago **Request:** ```json { "payment_method_id": "pm_..." } ``` --- ### GET `/api/v1/payment-methods` Lista métodos guardados --- ### DELETE `/api/v1/payment-methods/:id` Elimina método de pago --- ## 4. Implementation ```typescript // src/modules/payments/payment.controller.ts export class PaymentController { async createPaymentIntent(req: Request, res: Response) { const { amount, payment_method_id, description } = req.body; const userId = req.user!.id; const result = await paymentService.createPaymentIntent({ user_id: userId, amount, payment_method_id, description, }); return successResponse(res, result, 200); } async getPayments(req: Request, res: Response) { const userId = req.user!.id; const { status, limit = 20, offset = 0 } = req.query; const payments = await paymentService.getPayments({ user_id: userId, status, limit: Number(limit), offset: Number(offset), }); return successResponse(res, payments, 200); } async requestRefund(req: Request, res: Response) { const { id } = req.params; const { reason, amount } = req.body; const refund = await paymentService.createRefund({ payment_id: id, reason, amount, }); return successResponse(res, refund, 200); } } ``` --- ## 5. Validations ```typescript // Zod schemas export const createPaymentIntentSchema = z.object({ amount: z.number().positive(), payment_method_id: z.string().min(1), description: z.string().optional(), }); export const createSubscriptionSchema = z.object({ price_id: z.string().startsWith('price_'), payment_method_id: z.string().min(1), trial_days: z.number().optional(), }); export const refundSchema = z.object({ reason: z.enum(['duplicate', 'fraudulent', 'requested_by_customer']), amount: z.number().positive().optional(), }); ``` --- ## 6. Routes ```typescript // src/modules/payments/payment.routes.ts const router = Router(); // Payments router.post('/intent', authenticate, validate(createPaymentIntentSchema), controller.createPaymentIntent); router.get('/', authenticate, controller.getPayments); router.post('/:id/refund', authenticate, requireAdmin, validate(refundSchema), controller.requestRefund); // Subscriptions router.post('/subscriptions', authenticate, validate(createSubscriptionSchema), subscriptionController.create); router.get('/subscriptions', authenticate, subscriptionController.list); router.delete('/subscriptions/:id', authenticate, subscriptionController.cancel); // Payment Methods router.post('/payment-methods', authenticate, paymentMethodController.save); router.get('/payment-methods', authenticate, paymentMethodController.list); router.delete('/payment-methods/:id', authenticate, paymentMethodController.delete); router.patch('/payment-methods/:id/default', authenticate, paymentMethodController.setDefault); export default router; ```