API.md — Referencia general PolySignal Backend
Base URL (dev): http://localhost:7860
Base URL (prod, HF Spaces): misma URL que el frontend (mismo origen).
Arranque rápido
cd backend/
npm install
npm run db:migrate # solo primera vez
npm run db:seed # crea usuarios de prueba
npm run dev # http://localhost:7860
Usuarios de prueba: admin@polysignal.test / Admin123! y user@polysignal.test / User123!
Autenticación
El API usa JWT Bearer. Para obtener un token:
TOKEN=$(curl -s -X POST http://localhost:7860/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"admin@polysignal.test","password":"Admin123!"}' | jq -r '.data.token')
Enviarlo en cada request protegido:
Authorization: Bearer <token>
Endpoints
Públicos (sin auth)
| Método | Ruta | Descripción | Doc |
|---|---|---|---|
GET |
/api/v1/health |
Sanity check | AUTH.md |
POST |
/api/v1/auth/login |
Login → JWT | AUTH.md |
GET |
/api/v1/markets |
Lista mercados paginada | MARKETS.md |
GET |
/api/v1/markets/:id |
Detalle de mercado | MARKETS.md |
GET |
/api/v1/markets/:id/signal |
Señal AI del mercado | SIGNALS.md |
Protegidos (requieren Authorization: Bearer <token>)
| Método | Ruta | Descripción | Doc |
|---|---|---|---|
GET |
/api/v1/auth/me |
Perfil del usuario | AUTH.md |
POST |
/api/v1/positions |
Abrir posición | POSITIONS.md |
GET |
/api/v1/positions |
Listar posiciones | POSITIONS.md |
DELETE |
/api/v1/positions/:id |
Cerrar posición | POSITIONS.md |
POST |
/api/v1/watchlist |
Añadir a watchlist | WATCHLIST.md |
GET |
/api/v1/watchlist |
Listar watchlist | WATCHLIST.md |
DELETE |
/api/v1/watchlist/:marketId |
Eliminar de watchlist | WATCHLIST.md |
GET |
/api/v1/alerts |
Historial de alertas | ALERTS.md |
Contrato de respuesta
Todas las respuestas siguen el mismo envelope:
// éxito
{ "ok": true, "data": <payload>, "meta": { ...opcional } }
// error
{ "ok": false, "error": { "code": "ERROR_CODE", "message": "...", "details": [...] } }
Códigos HTTP: 200 lectura · 201 creación · 204 borrado · 400 validación · 401 no autenticado · 404 no encontrado · 409 conflicto · 429 rate limit · 500 server error.
Rate limiting
- Global: 200 req / 15 min / IP
POST /auth/login: 5 intentos / 15 min / IP
Headers de respuesta: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset.
WebSocket (Socket.io)
Conectar al mismo host que el backend:
import { io } from 'socket.io-client';
const socket = io('http://localhost:7860');
| Evento | Frecuencia | Descripción | Doc |
|---|---|---|---|
market_update |
cada 30s | Precio actualizado de un mercado | MARKETS.md |
ai_signal |
cada 5 min | Nueva señal AI generada | SIGNALS.md |
price_alert |
cuando se dispara | Alerta de precio threshold | ALERTS.md |
Importar en Insomnia / Postman
Ver insomnia-collection.json — export v4 listo para importar en Insomnia.
Pasos:
- Abrir Insomnia → Import → File
- Seleccionar
backend/docs/insomnia-collection.json - Configurar variable de entorno
base_url = http://localhost:7860 - Ejecutar
POST /auth/loginy copiar el token a la variabletoken
Variables de entorno completas
Ver backend/.env.example para la plantilla completa.
| Variable | Obligatoria | Descripción |
|---|---|---|
PORT |
Sí | Puerto del servidor (7860 para HF Spaces) |
DATABASE_URL |
Sí | Path SQLite: file:./polysignal.db |
JWT_SECRET |
Sí | Mínimo 32 chars |
JWT_EXPIRES_IN |
No | Default 1h |
BCRYPT_ROUNDS |
No | Default 10 |
CORS_ORIGIN |
No | Default http://localhost:5173 |
LOG_LEVEL |
No | Default info |
HF_TOKEN |
No | HuggingFace (señales AI reales) |
OPENROUTER_API_KEY |
No | Fallback LLM |
FINNHUB_API_KEY |
No | Noticias para señales |
TELEGRAM_BOT_TOKEN |
No | Alertas Telegram |