--- id: ET-MKT-002 title: Especificacion de API - Marketplace type: technical-spec status: Draft priority: High epic: OQI-009 project: trading-platform version: 1.0.0 dates: created: 2026-01-04 updated: 2026-01-04 tags: - marketplace - api - rest - endpoints --- # ET-MKT-002: Especificacion de API ## Resumen Este documento define los endpoints REST API para el modulo de Marketplace (OQI-009). Incluye endpoints para productos, compras, suscripciones, asesoria y visualizacion premium. ## Base URL ``` /api/v1/marketplace ``` ## Autenticacion Todos los endpoints requieren autenticacion via JWT Bearer token, excepto los marcados como publicos. ```http Authorization: Bearer ``` ## Endpoints de Productos ### GET /products Lista productos del marketplace. **Query Parameters:** | Parametro | Tipo | Requerido | Descripcion | |-----------|------|-----------|-------------| | category | string | No | Filtrar por categoria (slug) | | type | string | No | Filtrar por tipo de producto | | search | string | No | Busqueda en nombre/descripcion | | featured | boolean | No | Solo productos destacados | | sort | string | No | Ordenamiento: price_asc, price_desc, rating, newest | | page | number | No | Pagina (default: 1) | | limit | number | No | Items por pagina (default: 12, max: 50) | **Response 200:** ```json { "data": [ { "id": "550e8400-e29b-41d4-a716-446655440001", "name": "Pro Signal Pack", "slug": "pro-signal-pack", "shortDescription": "200 senales ML de alta confianza", "type": "signal_pack", "price": 29.00, "currency": "USD", "billingType": "one_time", "category": { "id": "cat-001", "name": "Senales", "slug": "signals" }, "isFeatured": true, "metadata": { "credits": 200, "validityDays": 60, "minConfidence": 80 } } ], "pagination": { "page": 1, "limit": 12, "total": 7, "totalPages": 1 } } ``` ### GET /products/:id Obtiene detalle de un producto. **Response 200:** ```json { "id": "550e8400-e29b-41d4-a716-446655440001", "name": "Pro Signal Pack", "slug": "pro-signal-pack", "description": "Paquete de 200 senales ML de alta confianza...", "shortDescription": "200 senales ML de alta confianza", "type": "signal_pack", "price": 29.00, "currency": "USD", "billingType": "one_time", "subscriptionInterval": null, "category": { "id": "cat-001", "name": "Senales", "slug": "signals" }, "isFeatured": true, "isActive": true, "metadata": { "credits": 200, "validityDays": 60, "minConfidence": 80 }, "relatedProducts": [ { "id": "550e8400-e29b-41d4-a716-446655440002", "name": "Basic Signal Pack", "price": 9.00 } ], "createdAt": "2026-01-04T00:00:00Z" } ``` ### GET /categories Lista categorias de productos. **Response 200:** ```json { "data": [ { "id": "cat-001", "name": "Senales", "slug": "signals", "description": "Paquetes de senales ML premium", "icon": "signal", "productCount": 3 } ] } ``` --- ## Endpoints de Compras ### POST /purchases Crea una nueva compra. **Request Body:** ```json { "productId": "550e8400-e29b-41d4-a716-446655440001", "paymentMethodId": "pm_1234567890", "quantity": 1, "acceptedTerms": true } ``` **Response 201:** ```json { "id": "purchase-001", "status": "completed", "product": { "id": "550e8400-e29b-41d4-a716-446655440001", "name": "Pro Signal Pack" }, "quantity": 1, "unitPrice": 29.00, "totalPrice": 29.00, "currency": "USD", "paymentId": "pi_abc123", "completedAt": "2026-01-04T12:00:00Z", "receipt": { "url": "https://receipts.stripe.com/...", "emailSent": true }, "activation": { "type": "signal_credits", "creditsAdded": 200, "newBalance": 215, "expiresAt": "2026-03-04T12:00:00Z" } } ``` **Response 402 (Pago Fallido):** ```json { "error": { "code": "PAYMENT_FAILED", "message": "El pago no pudo ser procesado", "details": { "declineCode": "insufficient_funds" } } } ``` ### GET /purchases Lista compras del usuario autenticado. **Query Parameters:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | status | string | Filtrar por estado | | productType | string | Filtrar por tipo de producto | | from | date | Fecha desde | | to | date | Fecha hasta | | page | number | Pagina | | limit | number | Items por pagina | **Response 200:** ```json { "data": [ { "id": "purchase-001", "product": { "id": "prod-001", "name": "Pro Signal Pack", "type": "signal_pack" }, "totalPrice": 29.00, "currency": "USD", "status": "completed", "completedAt": "2026-01-04T12:00:00Z" } ], "pagination": { "page": 1, "limit": 20, "total": 5 } } ``` ### GET /purchases/:id Obtiene detalle de una compra. **Response 200:** ```json { "id": "purchase-001", "product": { "id": "prod-001", "name": "Pro Signal Pack", "type": "signal_pack", "price": 29.00 }, "quantity": 1, "unitPrice": 29.00, "totalPrice": 29.00, "currency": "USD", "status": "completed", "paymentMethod": "visa ****4242", "completedAt": "2026-01-04T12:00:00Z", "receipt": { "url": "https://receipts.stripe.com/..." } } ``` --- ## Endpoints de Suscripciones ### POST /subscriptions Crea una nueva suscripcion. **Request Body:** ```json { "productId": "550e8400-e29b-41d4-a716-446655440003", "paymentMethodId": "pm_1234567890", "acceptedTerms": true } ``` **Response 201:** ```json { "id": "sub-001", "status": "active", "product": { "id": "prod-003", "name": "Unlimited Signals" }, "price": 49.00, "currency": "USD", "interval": "monthly", "currentPeriodStart": "2026-01-04T00:00:00Z", "currentPeriodEnd": "2026-02-04T00:00:00Z", "cancelAtPeriodEnd": false } ``` ### GET /subscriptions Lista suscripciones del usuario. **Response 200:** ```json { "data": [ { "id": "sub-001", "product": { "id": "prod-003", "name": "Unlimited Signals", "type": "signal_pack" }, "status": "active", "price": 49.00, "interval": "monthly", "currentPeriodEnd": "2026-02-04T00:00:00Z", "cancelAtPeriodEnd": false } ] } ``` ### DELETE /subscriptions/:id Cancela una suscripcion. **Request Body:** ```json { "reason": "No longer needed", "cancelImmediately": false } ``` **Response 200:** ```json { "id": "sub-001", "status": "active", "cancelAtPeriodEnd": true, "canceledAt": "2026-01-04T12:00:00Z", "accessEndsAt": "2026-02-04T00:00:00Z", "message": "Tu suscripcion se cancelara al final del periodo actual" } ``` --- ## Endpoints de Creditos de Senales ### GET /credits Obtiene creditos de senales del usuario. **Response 200:** ```json { "totalAvailable": 150, "hasUnlimited": false, "credits": [ { "id": "credit-001", "productName": "Pro Signal Pack", "initialAmount": 200, "remainingAmount": 150, "expiresAt": "2026-03-04T12:00:00Z", "isUnlimited": false } ], "usage": { "today": 3, "thisWeek": 15, "thisMonth": 50 } } ``` ### GET /credits/history Historial de uso de creditos. **Response 200:** ```json { "data": [ { "id": "delivery-001", "signal": { "id": "sig-001", "symbol": "BTC/USDT", "action": "BUY", "confidence": 87.5 }, "deliveredAt": "2026-01-04T14:30:00Z", "channel": "both" } ], "pagination": { "page": 1, "limit": 20, "total": 50 } } ``` --- ## Endpoints de Asesoria ### GET /advisors Lista asesores disponibles. **Query Parameters:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | specialty | string | Filtrar por especialidad | | language | string | Filtrar por idioma | | minRating | number | Rating minimo | | sort | string | rating, price, experience | | page | number | Pagina | | limit | number | Items por pagina | **Response 200:** ```json { "data": [ { "id": "advisor-001", "displayName": "Maria Garcia, CFA", "title": "Crypto Trading Expert", "shortBio": "10 anos de experiencia en mercados crypto...", "specialties": ["crypto", "defi", "technical_analysis"], "experienceYears": 10, "languages": ["es", "en"], "rating": 4.9, "reviewCount": 85, "completedSessions": 120, "priceFrom": 49.00, "profileImageUrl": "https://...", "nextAvailable": "2026-01-05T09:00:00Z" } ], "pagination": { "page": 1, "limit": 10, "total": 5 } } ``` ### GET /advisors/:id Obtiene perfil completo de un asesor. **Response 200:** ```json { "id": "advisor-001", "displayName": "Maria Garcia, CFA", "title": "Crypto Trading Expert", "bio": "Analista certificada CFA con 10 anos de experiencia...", "shortBio": "10 anos de experiencia en mercados crypto...", "specialties": ["crypto", "defi", "technical_analysis"], "experienceYears": 10, "languages": ["es", "en"], "rating": 4.9, "reviewCount": 85, "completedSessions": 120, "profileImageUrl": "https://...", "isVerified": true, "sessionOptions": [ { "duration": 30, "price": 49.00, "currency": "USD", "includes": ["video", "notes"] }, { "duration": 60, "price": 89.00, "currency": "USD", "includes": ["video", "notes", "action_plan"] }, { "duration": 90, "price": 119.00, "currency": "USD", "includes": ["video", "notes", "action_plan", "follow_up"] } ], "reviews": [ { "id": "review-001", "rating": 5, "comment": "Excelente sesion, muy profesional", "userName": "Juan P.", "createdAt": "2026-01-03T00:00:00Z" } ] } ``` ### GET /advisors/:id/availability Obtiene disponibilidad de un asesor. **Query Parameters:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | duration | number | Duracion de sesion en minutos | | timezone | string | Zona horaria del usuario | | from | date | Fecha desde | | to | date | Fecha hasta | **Response 200:** ```json { "advisorId": "advisor-001", "duration": 60, "timezone": "America/Mexico_City", "slots": [ { "date": "2026-01-06", "times": ["09:00", "10:00", "11:00", "14:00", "15:00"] }, { "date": "2026-01-07", "times": ["09:00", "10:00", "14:00"] } ] } ``` ### POST /advisory-sessions Agenda una sesion de asesoria. **Request Body:** ```json { "advisorId": "advisor-001", "productId": "prod-advisory-60", "scheduledAt": "2026-01-06T10:00:00-06:00", "timezone": "America/Mexico_City", "paymentMethodId": "pm_1234567890", "notes": "Quiero discutir mi estrategia de DeFi" } ``` **Response 201:** ```json { "id": "session-001", "advisor": { "id": "advisor-001", "displayName": "Maria Garcia, CFA" }, "duration": 60, "scheduledAt": "2026-01-06T16:00:00Z", "scheduledAtLocal": "2026-01-06T10:00:00-06:00", "timezone": "America/Mexico_City", "status": "scheduled", "price": 89.00, "currency": "USD", "calEventId": "cal-event-123", "joinUrl": null, "confirmationEmailSent": true } ``` ### GET /advisory-sessions Lista sesiones del usuario. **Query Parameters:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | status | string | scheduled, completed, cancelled | | from | date | Fecha desde | | to | date | Fecha hasta | **Response 200:** ```json { "data": [ { "id": "session-001", "advisor": { "id": "advisor-001", "displayName": "Maria Garcia, CFA", "profileImageUrl": "https://..." }, "duration": 60, "scheduledAt": "2026-01-06T16:00:00Z", "status": "scheduled", "joinUrl": "https://daily.co/room-xyz", "canReschedule": true, "canCancel": true } ] } ``` ### GET /advisory-sessions/:id Obtiene detalle de una sesion. **Response 200:** ```json { "id": "session-001", "advisor": { "id": "advisor-001", "displayName": "Maria Garcia, CFA", "profileImageUrl": "https://..." }, "duration": 60, "scheduledAt": "2026-01-06T16:00:00Z", "endedAt": null, "status": "scheduled", "joinUrl": "https://daily.co/room-xyz", "recordingUrl": null, "notes": { "summary": null, "recommendations": [], "resources": [], "followUpActions": [] }, "review": null, "canReschedule": true, "canCancel": true, "cancellationPolicy": { "fullRefundBefore": "2026-01-05T16:00:00Z", "partialRefundBefore": "2026-01-06T04:00:00Z" } } ``` ### PATCH /advisory-sessions/:id Reagenda una sesion. **Request Body:** ```json { "scheduledAt": "2026-01-07T14:00:00-06:00", "timezone": "America/Mexico_City" } ``` **Response 200:** ```json { "id": "session-001", "scheduledAt": "2026-01-07T20:00:00Z", "status": "scheduled", "message": "Sesion reagendada exitosamente" } ``` ### DELETE /advisory-sessions/:id Cancela una sesion. **Request Body:** ```json { "reason": "Schedule conflict" } ``` **Response 200:** ```json { "id": "session-001", "status": "cancelled", "cancelledAt": "2026-01-04T12:00:00Z", "refund": { "amount": 89.00, "percentage": 100, "status": "processing" } } ``` ### POST /advisory-sessions/:id/notes Asesor agrega notas a la sesion. **Request Body:** ```json { "summary": "Discutimos estrategias de DeFi y riesgos...", "recommendations": [ "Diversificar en multiples protocolos", "Implementar stop-loss automaticos" ], "resources": [ { "title": "Guia de DeFi Seguro", "url": "https://..." } ], "followUpActions": [ "Revisar portfolio actual", "Configurar alertas de precio" ] } ``` **Response 201:** ```json { "id": "notes-001", "sessionId": "session-001", "createdAt": "2026-01-06T18:00:00Z", "notificationSent": true } ``` ### POST /advisory-sessions/:id/reviews Usuario deja review de la sesion. **Request Body:** ```json { "rating": 5, "comment": "Excelente sesion, Maria es muy profesional y conocedora", "isPublic": true } ``` **Response 201:** ```json { "id": "review-001", "rating": 5, "comment": "Excelente sesion...", "isPublic": true, "createdAt": "2026-01-06T19:00:00Z" } ``` --- ## Endpoints de Visualizacion Premium ### GET /visualization/subscription Obtiene estado de suscripcion de visualizacion. **Response 200:** ```json { "isActive": true, "subscription": { "id": "vis-sub-001", "startedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-02-01T00:00:00Z", "cancelAtPeriodEnd": false }, "features": [ "ml_indicators", "unlimited_backtest", "unlimited_alerts", "multi_chart_4" ], "limits": { "alerts": -1, "layouts": -1, "backtestDays": -1, "charts": 4 } } ``` ### POST /visualization/subscribe Crea suscripcion de visualizacion premium. **Request Body:** ```json { "paymentMethodId": "pm_1234567890", "acceptedTerms": true } ``` **Response 201:** ```json { "subscription": { "id": "vis-sub-001", "status": "active", "startedAt": "2026-01-04T00:00:00Z", "expiresAt": "2026-02-04T00:00:00Z" }, "features": [ "ml_indicators", "unlimited_backtest", "unlimited_alerts", "multi_chart_4" ], "message": "Visualizacion Premium activada" } ``` ### GET /visualization/indicators Lista indicadores disponibles. **Response 200:** ```json { "basic": [ { "id": "sma", "name": "Simple Moving Average", "type": "overlay", "available": true }, { "id": "rsi", "name": "Relative Strength Index", "type": "panel", "available": true } ], "premium": [ { "id": "ml_range_predictor", "name": "Range Predictor", "type": "overlay", "description": "Predice rangos de precio", "available": true, "requiresPremium": true }, { "id": "ml_amd_detector", "name": "AMD Detector", "type": "overlay", "description": "Detecta patrones AMD", "available": true, "requiresPremium": true } ] } ``` ### GET /visualization/layouts Lista layouts guardados del usuario. **Response 200:** ```json { "data": [ { "id": "layout-001", "name": "Mi Layout Principal", "isDefault": true, "chartCount": 4, "createdAt": "2026-01-03T00:00:00Z" } ], "limits": { "max": -1, "used": 3 } } ``` ### POST /visualization/layouts Guarda un nuevo layout. **Request Body:** ```json { "name": "Crypto Watch", "layoutConfig": { "grid": "2x2", "charts": [ {"position": 0, "symbol": "BTC/USDT", "timeframe": "4H"}, {"position": 1, "symbol": "ETH/USDT", "timeframe": "4H"}, {"position": 2, "symbol": "SOL/USDT", "timeframe": "4H"}, {"position": 3, "symbol": "AVAX/USDT", "timeframe": "4H"} ] }, "indicators": [ {"chartIndex": 0, "indicators": ["ml_range_predictor", "sma"]}, {"chartIndex": 1, "indicators": ["ml_amd_detector"]} ], "isDefault": false } ``` **Response 201:** ```json { "id": "layout-002", "name": "Crypto Watch", "isDefault": false, "createdAt": "2026-01-04T12:00:00Z" } ``` ### POST /visualization/alerts Crea una alerta de indicador. **Request Body:** ```json { "indicatorId": "ml_amd_detector", "symbol": "BTC/USDT", "conditions": [ { "field": "phase", "operator": "equals", "value": "distribution" } ], "notificationChannels": ["push", "email"], "triggerOnce": false } ``` **Response 201:** ```json { "id": "alert-001", "indicatorId": "ml_amd_detector", "symbol": "BTC/USDT", "isActive": true, "createdAt": "2026-01-04T12:00:00Z" } ``` ### POST /visualization/backtest Ejecuta un backtest. **Request Body:** ```json { "symbol": "BTC/USDT", "strategyConfig": { "indicators": ["ml_amd_detector", "ml_signal_overlay"], "entryConditions": [...], "exitConditions": [...] }, "periodStart": "2025-10-01", "periodEnd": "2026-01-01", "initialCapital": 10000 } ``` **Response 200:** ```json { "id": "backtest-001", "symbol": "BTC/USDT", "periodStart": "2025-10-01", "periodEnd": "2026-01-01", "initialCapital": 10000.00, "finalCapital": 12450.00, "totalReturn": 0.245, "totalTrades": 45, "winningTrades": 30, "losingTrades": 15, "winRate": 66.67, "profitFactor": 2.3, "maxDrawdown": -8.5, "sharpeRatio": 1.82, "trades": [ { "entryDate": "2025-10-05T14:00:00Z", "exitDate": "2025-10-06T10:00:00Z", "entryPrice": 42150.00, "exitPrice": 43200.00, "side": "long", "pnl": 250.00, "pnlPercent": 2.49 } ] } ``` --- ## Webhooks ### POST /webhooks/stripe Procesa eventos de Stripe. **Headers:** ```http Stripe-Signature: t=1234567890,v1=signature... ``` **Eventos Soportados:** - `payment_intent.succeeded` - `payment_intent.payment_failed` - `customer.subscription.created` - `customer.subscription.updated` - `customer.subscription.deleted` - `invoice.paid` - `invoice.payment_failed` ### POST /webhooks/cal Procesa eventos de Cal.com. **Eventos Soportados:** - `BOOKING_CREATED` - `BOOKING_CANCELLED` - `BOOKING_RESCHEDULED` - `MEETING_ENDED` **Payload Ejemplo:** ```json { "triggerEvent": "BOOKING_CREATED", "payload": { "bookingId": 12345, "uid": "booking-uid-123", "startTime": "2026-01-06T16:00:00Z", "endTime": "2026-01-06T17:00:00Z", "attendees": [ { "email": "user@example.com", "name": "Juan Perez" } ], "metadata": { "sessionId": "session-001" } } } ``` ### POST /webhooks/daily Procesa eventos de Daily.co. **Eventos Soportados:** - `meeting.started` - `meeting.ended` - `recording.ready` --- ## Codigos de Error | Codigo | HTTP Status | Descripcion | |--------|-------------|-------------| | PRODUCT_NOT_FOUND | 404 | Producto no encontrado | | PRODUCT_UNAVAILABLE | 400 | Producto no disponible | | INSUFFICIENT_CREDITS | 400 | Creditos insuficientes | | PAYMENT_FAILED | 402 | Pago fallido | | SUBSCRIPTION_EXISTS | 409 | Ya existe suscripcion activa | | ADVISOR_NOT_AVAILABLE | 400 | Asesor no disponible | | SLOT_NOT_AVAILABLE | 409 | Horario no disponible | | SESSION_NOT_CANCELLABLE | 400 | Sesion no puede cancelarse | | PREMIUM_REQUIRED | 403 | Requiere suscripcion premium | | LIMIT_EXCEEDED | 400 | Limite excedido | **Formato de Error:** ```json { "error": { "code": "PAYMENT_FAILED", "message": "El pago no pudo ser procesado", "details": { "declineCode": "insufficient_funds" }, "timestamp": "2026-01-04T12:00:00Z", "requestId": "req-abc123" } } ``` --- ## Rate Limiting | Endpoint | Limite | Ventana | |----------|--------|---------| | GET /products | 100 | 1 minuto | | POST /purchases | 10 | 1 minuto | | POST /subscriptions | 5 | 1 minuto | | POST /advisory-sessions | 10 | 1 hora | | POST /visualization/backtest | 20 | 1 hora | **Headers de Rate Limit:** ```http X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1704369600 ``` --- ## Referencias - [ET-MKT-001: Database](./ET-MKT-001-database.md) - [RF-MKT-001: Catalogo](../requerimientos/RF-MKT-001-catalogo.md) - [RF-MKT-002: Senales Premium](../requerimientos/RF-MKT-002-senales-premium.md) - [RF-MKT-003: Asesoria](../requerimientos/RF-MKT-003-asesoria.md) - [RF-MKT-004: Visualizacion](../requerimientos/RF-MKT-004-visualizacion.md)