CRITICAL fixes: - Restrict X-View-Tenant impersonation to global admin only (was any admin) - Add authorization to subscription endpoints (was open to any user) - Make webhook signature verification mandatory (was skippable) - Remove databaseName from JWT payload (resolve server-side with cache) - Reduce body size limit from 1GB to 10MB (50MB for bulk CFDI) - Restrict .env file permissions to 600 HIGH fixes: - Add authorization to SAT cron endpoints (global admin only) - Add Content-Security-Policy and Permissions-Policy headers - Centralize isGlobalAdmin() utility with caching - Add rate limiting on auth endpoints (express-rate-limit) - Require authentication on logout endpoint MEDIUM fixes: - Replace Math.random() with crypto.randomBytes for temp passwords - Remove console.log of temporary passwords in production - Remove DB credentials from admin notification email - Add escapeHtml() to email templates (prevent HTML injection) - Add file size validation on FIEL upload (50KB max) - Require TLS for SMTP connections - Normalize email to lowercase before uniqueness check - Remove hardcoded default for FIEL_ENCRYPTION_KEY Also includes: - Complete production deployment documentation - API reference documentation - Security audit report with remediation details - Updated README with v0.5.0 changelog - New client admin email template - Utility scripts (create-carlos, test-emails) - PM2 ecosystem config updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
324 lines
6.5 KiB
Markdown
324 lines
6.5 KiB
Markdown
# API Reference - Horux360
|
|
|
|
**Base URL:** `https://horuxfin.com/api`
|
|
|
|
---
|
|
|
|
## Autenticación
|
|
|
|
Todos los endpoints (excepto auth) requieren header:
|
|
```
|
|
Authorization: Bearer <accessToken>
|
|
```
|
|
|
|
### Rate Limits (por IP)
|
|
| Endpoint | Límite | Ventana |
|
|
|----------|--------|---------|
|
|
| `POST /auth/login` | 10 requests | 15 minutos |
|
|
| `POST /auth/register` | 3 requests | 1 hora |
|
|
| `POST /auth/refresh` | 20 requests | 15 minutos |
|
|
| General `/api/*` | 30 requests/s | burst 50 |
|
|
|
|
---
|
|
|
|
## Auth (`/api/auth`)
|
|
|
|
### `POST /auth/register`
|
|
Registra nueva empresa y usuario admin. Provisiona base de datos dedicada.
|
|
|
|
**Body:**
|
|
```json
|
|
{
|
|
"empresa": { "nombre": "Mi Empresa", "rfc": "ABC123456789" },
|
|
"usuario": { "nombre": "Juan", "email": "juan@empresa.com", "password": "min8chars" }
|
|
}
|
|
```
|
|
|
|
**Response:** `{ accessToken, refreshToken, user: UserInfo }`
|
|
|
|
### `POST /auth/login`
|
|
```json
|
|
{ "email": "usuario@empresa.com", "password": "..." }
|
|
```
|
|
**Response:** `{ accessToken, refreshToken, user: UserInfo }`
|
|
|
|
### `POST /auth/refresh`
|
|
```json
|
|
{ "refreshToken": "..." }
|
|
```
|
|
**Response:** `{ accessToken, refreshToken }`
|
|
|
|
### `POST /auth/logout` *(requiere auth)*
|
|
```json
|
|
{ "refreshToken": "..." }
|
|
```
|
|
|
|
### `GET /auth/me` *(requiere auth)*
|
|
**Response:** `UserInfo`
|
|
|
|
---
|
|
|
|
## Dashboard (`/api/dashboard`)
|
|
|
|
### `GET /dashboard/kpis?año=2026&mes=3`
|
|
KPIs principales: ingresos, egresos, utilidad, margen, IVA balance, conteo de CFDIs.
|
|
|
|
### `GET /dashboard/ingresos-egresos?año=2026`
|
|
Datos mensuales de ingresos/egresos para gráfica anual.
|
|
|
|
### `GET /dashboard/resumen-fiscal?año=2026&mes=3`
|
|
IVA por pagar, IVA a favor, ISR, declaraciones pendientes, próxima obligación.
|
|
|
|
### `GET /dashboard/alertas?limit=5`
|
|
Alertas activas no resueltas, ordenadas por prioridad.
|
|
|
|
---
|
|
|
|
## CFDI (`/api/cfdi`)
|
|
|
|
### `GET /cfdi?page=1&limit=20&tipo=ingreso&search=...`
|
|
Lista paginada de CFDIs con filtros.
|
|
|
|
### `GET /cfdi/resumen`
|
|
Resumen de conteo por tipo y estado.
|
|
|
|
### `GET /cfdi/emisores`
|
|
Lista de emisores únicos.
|
|
|
|
### `GET /cfdi/receptores`
|
|
Lista de receptores únicos.
|
|
|
|
### `GET /cfdi/:id`
|
|
Detalle de un CFDI.
|
|
|
|
### `GET /cfdi/:id/xml`
|
|
XML original del CFDI.
|
|
|
|
### `POST /cfdi`
|
|
Crear un CFDI individual. Sujeto a límite de plan.
|
|
|
|
### `POST /cfdi/bulk`
|
|
Carga masiva de CFDIs. Body limit: 50MB. Sujeto a límite de plan.
|
|
|
|
### `DELETE /cfdi/:id`
|
|
Eliminar un CFDI.
|
|
|
|
---
|
|
|
|
## Impuestos (`/api/impuestos`)
|
|
|
|
### `GET /impuestos/iva?año=2026`
|
|
Datos mensuales de IVA (trasladado, acreditable, resultado, acumulado).
|
|
|
|
---
|
|
|
|
## Alertas (`/api/alertas`)
|
|
|
|
### `GET /alertas`
|
|
### `POST /alertas`
|
|
### `PUT /alertas/:id`
|
|
### `DELETE /alertas/:id`
|
|
### `PATCH /alertas/:id/read`
|
|
### `PATCH /alertas/:id/resolve`
|
|
|
|
---
|
|
|
|
## Calendario (`/api/calendario`)
|
|
|
|
### `GET /calendario?año=2026&mes=3`
|
|
### `POST /calendario`
|
|
### `PUT /calendario/:id`
|
|
### `DELETE /calendario/:id`
|
|
|
|
---
|
|
|
|
## Reportes (`/api/reportes`)
|
|
|
|
### `GET /reportes/flujo-efectivo?año=2026`
|
|
### `GET /reportes/impuestos?año=2026`
|
|
### `GET /reportes/forecasting?año=2026`
|
|
### `GET /reportes/concentrado?año=2026`
|
|
|
|
---
|
|
|
|
## Export (`/api/export`)
|
|
|
|
### `GET /export/cfdis?format=excel&tipo=ingreso`
|
|
Exporta CFDIs a Excel o CSV.
|
|
|
|
---
|
|
|
|
## FIEL (`/api/fiel`)
|
|
|
|
### `POST /fiel/upload`
|
|
```json
|
|
{
|
|
"cerFile": "<base64>",
|
|
"keyFile": "<base64>",
|
|
"password": "..."
|
|
}
|
|
```
|
|
- Archivos max 50KB cada uno
|
|
- Password max 256 caracteres
|
|
|
|
### `GET /fiel/status`
|
|
Estado actual de la FIEL configurada.
|
|
|
|
### `DELETE /fiel`
|
|
Eliminar credenciales FIEL.
|
|
|
|
---
|
|
|
|
## SAT Sync (`/api/sat`)
|
|
|
|
### `POST /sat/sync`
|
|
Iniciar sincronización manual.
|
|
```json
|
|
{ "type": "daily", "dateFrom": "2026-01-01", "dateTo": "2026-01-31" }
|
|
```
|
|
|
|
### `GET /sat/sync/status`
|
|
Estado actual de sincronización.
|
|
|
|
### `GET /sat/sync/history?page=1&limit=10`
|
|
Historial de sincronizaciones.
|
|
|
|
### `GET /sat/sync/:id`
|
|
Detalle de un job de sincronización.
|
|
|
|
### `POST /sat/sync/:id/retry`
|
|
Reintentar un job fallido.
|
|
|
|
### `GET /sat/cron` *(admin global)*
|
|
Info del job programado.
|
|
|
|
### `POST /sat/cron/run` *(admin global)*
|
|
Ejecutar sincronización global manualmente.
|
|
|
|
---
|
|
|
|
## Usuarios (`/api/usuarios`)
|
|
|
|
### `GET /usuarios`
|
|
Usuarios del tenant actual.
|
|
|
|
### `GET /usuarios/all` *(admin global)*
|
|
Todos los usuarios de todas las empresas.
|
|
|
|
### `POST /usuarios`
|
|
Invitar usuario (genera password temporal con `crypto.randomBytes`).
|
|
```json
|
|
{ "email": "nuevo@empresa.com", "nombre": "María", "role": "contador" }
|
|
```
|
|
|
|
### `PUT /usuarios/:id`
|
|
Actualizar usuario (nombre, role, active).
|
|
|
|
### `DELETE /usuarios/:id`
|
|
|
|
### `PUT /usuarios/:id/global` *(admin global)*
|
|
Actualizar usuario de cualquier empresa.
|
|
|
|
### `DELETE /usuarios/:id/global` *(admin global)*
|
|
|
|
---
|
|
|
|
## Tenants / Clientes (`/api/tenants`) *(admin global)*
|
|
|
|
### `GET /tenants`
|
|
Lista de todos los tenants/clientes.
|
|
|
|
### `POST /tenants`
|
|
Crear nuevo tenant. Provisiona base de datos. Envía email al admin.
|
|
```json
|
|
{
|
|
"nombre": "Empresa Nueva",
|
|
"rfc": "ENE123456789",
|
|
"plan": "business",
|
|
"adminNombre": "Pedro",
|
|
"adminEmail": "pedro@nueva.com"
|
|
}
|
|
```
|
|
|
|
### `PUT /tenants/:id`
|
|
Actualizar tenant (plan, limits, active).
|
|
|
|
### `DELETE /tenants/:id`
|
|
Soft delete — renombra la base de datos a `*_deleted_*`.
|
|
|
|
---
|
|
|
|
## Suscripciones (`/api/subscriptions`) *(admin global)*
|
|
|
|
### `GET /subscriptions/:tenantId`
|
|
Suscripción activa del tenant.
|
|
|
|
### `POST /subscriptions/:tenantId/generate-link`
|
|
Generar link de pago MercadoPago.
|
|
|
|
### `POST /subscriptions/:tenantId/mark-paid`
|
|
Marcar como pagado manualmente.
|
|
```json
|
|
{ "amount": 999 }
|
|
```
|
|
|
|
### `GET /subscriptions/:tenantId/payments`
|
|
Historial de pagos.
|
|
|
|
---
|
|
|
|
## Webhooks (`/api/webhooks`)
|
|
|
|
### `POST /webhooks/mercadopago`
|
|
Webhook de MercadoPago. Requiere headers:
|
|
- `x-signature`: Firma HMAC-SHA256
|
|
- `x-request-id`: ID del request
|
|
|
|
---
|
|
|
|
## Roles y Permisos
|
|
|
|
| Rol | Descripción | Acceso |
|
|
|-----|-------------|--------|
|
|
| `admin` | Administrador del tenant | Todo dentro de su tenant + invitar usuarios |
|
|
| `contador` | Contador | CFDI, impuestos, reportes, dashboard |
|
|
| `visor` | Solo lectura | Dashboard, CFDI (solo ver), reportes |
|
|
|
|
### Admin Global
|
|
El admin del tenant con RFC `CAS2408138W2` tiene acceso adicional:
|
|
- Gestión de todos los tenants
|
|
- Suscripciones
|
|
- SAT cron
|
|
- Impersonación via `X-View-Tenant` header
|
|
- Bypass de plan limits al impersonar
|
|
|
|
---
|
|
|
|
## Tipos Compartidos (`@horux/shared`)
|
|
|
|
### UserInfo
|
|
```typescript
|
|
interface UserInfo {
|
|
id: string;
|
|
email: string;
|
|
nombre: string;
|
|
role: 'admin' | 'contador' | 'visor';
|
|
tenantId: string;
|
|
tenantName: string;
|
|
tenantRfc: string;
|
|
plan: string;
|
|
}
|
|
```
|
|
|
|
### JWTPayload
|
|
```typescript
|
|
interface JWTPayload {
|
|
userId: string;
|
|
email: string;
|
|
role: Role;
|
|
tenantId: string;
|
|
iat?: number;
|
|
exp?: number;
|
|
}
|
|
```
|