---
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;
```
