Referencia de la API
API REST en JSON. Todas las rutas cuelgan de /api.
| Entorno | URL base |
|---|---|
| Desarrollo local | http://localhost:3000/api |
| Producción (Vercel) | https://<dominio-de-la-app>/api |
Autenticación
Casi todos los endpoints requieren un access token JWT en la cabecera:
Authorization: Bearer <token>
El token se obtiene con POST /api/auth/login y dura 8 horas por defecto. Cuando vence, se renueva con POST /api/auth/refresh.
Payload del token:
{ "sub": "<uuid del usuario>", "role": "admin | advisor | client", "email": "...", "iat": 0, "exp": 0 }
En esta referencia, cada endpoint indica su nivel de acceso:
| Etiqueta | Significado |
|---|---|
| Público | No requiere token |
| Público (auth opcional) | Funciona sin token; con token de admin habilita campos extra |
| Autenticado | Cualquier rol con token válido |
| admin / advisor / client | Solo esos roles |
Formato de errores
Todas las respuestas de error tienen esta forma:
{
"error": "CODIGO_EN_MAYUSCULAS",
"message": "Descripción legible",
"details": { }
}
details es opcional. En errores de validación contiene el resultado de ZodError.flatten():
{
"error": "VALIDATION_ERROR",
"message": "Invalid request",
"details": {
"formErrors": [],
"fieldErrors": { "email": ["Invalid email"] }
}
}
Códigos comunes
| HTTP | error | Cuándo |
|---|---|---|
| 400 | VALIDATION_ERROR | El cuerpo o los parámetros no cumplen el esquema |
| 400 | EMPTY_PATCH | Un PUT/PATCH sin campos para actualizar |
| 401 | UNAUTHENTICATED | Falta el token |
| 401 | INVALID_TOKEN | Token inválido o vencido |
| 403 | FORBIDDEN | El rol no tiene permiso |
| 404 | NOT_FOUND | Recurso inexistente, fuera de tu alcance o ruta inexistente |
| 409 | DUPLICATE_* | Violación de unicidad (NIT, email) |
| 422 | varios | Regla de negocio incumplida (p. ej. ROUTE_CLOSED) |
| 500 | INTERNAL | Error no controlado |
| 502 | SIIGO_* | Falla al hablar con SIIGO |
Convenciones
- Nombres en camelCase en JSON (
priceListId), aunque la base de datos use snake_case. Algunos endpoints de listado devuelven filas crudas en snake_case (se indica en cada caso). - IDs son UUID v4, salvo los IDs de SIIGO (cadenas) y
siigoSellerId(entero). - Creación responde
201con{ "id": "<uuid>" }, salvo que se indique otra cosa. - Borrado responde
204sin cuerpo. Rutas y usuarios se desactivan (active = false); los demás recursos se borran físicamente. - Actualizaciones parciales: los
PUTaceptan cualquier subconjunto de campos. En varios recursos se usaCOALESCE, por lo que enviarnullno borra el valor (se indica en cada recurso). - Montos en pesos colombianos (COP) como número.
- Fechas en ISO 8601. La zona horaria de negocio es
America/Bogota. - Límites: cuerpo JSON máximo de 2 MB; imágenes máximo 5 MB.
Índice de endpoints
Salud
| Método | Ruta | Acceso |
|---|---|---|
| GET | /api/health | Público |
200 { "ok": true, "ts": "...", "db": "connected" } o 503 { "ok": false, "db": "<error>" } si la base de datos no responde.
Recursos
| Método | Ruta | Acceso | Página |
|---|---|---|---|
| POST | /api/auth/login | Público | Auth |
| POST | /api/auth/refresh | Público | Auth |
| GET | /api/auth/me | Autenticado | Auth |
| GET | /api/products | Autenticado | Productos |
| GET | /api/products/catalog | Público | Productos |
| POST | /api/products | admin | Productos |
| PUT | /api/products/:id | admin | Productos |
| POST | /api/products/:id/image | admin | Productos |
| GET | /api/quotations | Autenticado | Cotizaciones |
| POST | /api/quotations | client | Cotizaciones |
| GET | /api/quotations/:id | Autenticado | Cotizaciones |
| PATCH | /api/quotations/:id | admin, advisor | Cotizaciones |
| PATCH | /api/quotations/:id/status | admin, advisor | Cotizaciones |
| POST | /api/quotations/:id/comments | Autenticado | Cotizaciones |
| POST | /api/quotations/:id/clone | client | Cotizaciones |
| GET | /api/routes | Autenticado | Rutas |
| GET | /api/routes/me/cutoff | client | Rutas |
| POST | /api/routes | admin | Rutas |
| PUT | /api/routes/:id | admin | Rutas |
| DELETE | /api/routes/:id | admin | Rutas |
| GET | /api/categories | Autenticado o API key catalog:read | Categorías |
| POST / PUT / DELETE | /api/categories[/:id] | admin | Categorías |
| GET | /api/price-lists | Autenticado | Listas de precios |
| POST / PUT / DELETE | /api/price-lists[/:id] | admin | Listas de precios |
| GET | /api/price-lists/:id/products | Autenticado | Listas de precios |
| POST | /api/price-lists/:id/products | admin | Listas de precios |
| PUT | /api/price-lists/:id/clients | admin | Listas de precios |
| GET | /api/companies | Autenticado | Empresas |
| POST | /api/companies | Público | Empresas |
| PUT / DELETE | /api/companies/:id | admin | Empresas |
| POST | /api/companies/:id/branches | Público (auth opcional) | Empresas |
| PUT / DELETE | /api/companies/:id/branches/:branchId | admin | Empresas |
| GET | /api/promotions | Autenticado | Promociones |
| POST / PUT / DELETE | /api/promotions[/:id] | admin | Promociones |
| GET | /api/users | admin | Usuarios |
| POST | /api/users | Público (auth opcional) | Usuarios |
| PUT / DELETE | /api/users/:id | admin | Usuarios |
| GET | /api/stats/admin | admin | Estadísticas |
| GET | /api/stats/advisor | admin, advisor | Estadísticas |
| GET | /api/advisor/clients | admin, advisor | Asesor |
| GET | /api/advisor/clients/:clientId/quotations | admin, advisor | Asesor |
| GET | /api/advisor/companies | admin, advisor | Asesor |
| GET | /api/my-company | client | Mi empresa |
| POST / PUT / DELETE | /api/my-company/users[/:id] | client | Mi empresa |
| POST / PUT / DELETE | /api/my-company/branches[/:id] | client | Mi empresa |
| GET / POST / DELETE | /api/api-keys[/:id] | admin | API keys de integración |
| * | /api/integrations/siigo/* | admin | SIIGO |
Colección de Postman
En la raíz del repositorio está daval_api.postman_collection.json (y la carpeta postman/) con ejemplos listos para importar.