API REST¶
Eval360Pro expone una API REST con documentación interactiva via Swagger / OpenAPI.
Acceso a Swagger UI¶
En producción, /swagger muestra la API pública (/api/v1), pensada para integradores:
https://{slug}.eval360pro.com/swagger
Ahí ves los endpoints públicos, sus schemas y puedes probarlos autenticándote con tu API key
(botón Authorize → X-Api-Key; la clave se crea en Integraciones).
En desarrollo (la app corriendo en local) el mismo /swagger incluye además la API interna
completa (autenticación JWT). La API interna no se expone en producción.
Autenticación¶
Dos esquemas soportados (según el endpoint):
A) JWT Bearer (recomendado para clientes API)¶
- Obtener token:
POST /api/auth/token Content-Type: application/json { "email": "tu@email.com", "password": "tu-password", "tenantSlug": "acme" // opcional si el subdominio ya identifica el tenant }
Respuesta:
{
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"expiresInSeconds": 3600,
"user": { "id": "...", "email": "...", "fullName": "...", "roles": [...] }
}
-
Usar el token en cada request:
GET /api/employees Authorization: Bearer eyJ... -
Renovar antes de que expire (~1 hora):
POST /api/auth/refresh Content-Type: application/json { "refreshToken": "eyJ..." } -
Logout (invalida el refresh token):
POST /api/auth/logout Authorization: Bearer eyJ...
B) Cookie (para integraciones desde browser)¶
Si tu cliente es un browser ya logueado en la app, las cookies se envían automáticamente. Funciona en endpoints que aceptan ambos schemes (AuthSchemes.Cookie + AuthSchemes.Jwt).
Códigos de error estándar¶
| HTTP | errorCode | Significado |
|---|---|---|
| 400 | VALIDATION |
Body inválido. Ver validationErrors[] con campo + mensaje |
| 400 | BAD_REQUEST |
Request malformado |
| 401 | (sin body) | Token ausente o inválido |
| 403 | (sin body) | Autenticado pero sin rol |
| 403 | TENANT_SUSPENDED |
El tenant del usuario está suspendido |
| 403 | TENANT_CANCELLED |
El tenant del usuario fue cancelado |
| 404 | NOT_FOUND |
Recurso no existe |
| 409 | ONBOARDING_REQUIRED |
El tenant no completó el wizard de onboarding |
| 409 | PLAN_LIMIT_EMPLOYEES |
Se superaría el límite del plan al crear empleados |
| 409 | PLAN_LIMIT_CYCLES |
Se superaría el límite de ciclos del año |
| 429 | RATE_LIMITED |
Demasiados requests. Esperar y reintentar |
| 500 | (sin body) | Error interno. Mirar audit log + Serilog |
Forma del body de error:
{
"success": false,
"errorCode": "PLAN_LIMIT_EMPLOYEES",
"errorMessage": "El plan 'Starter' permite 50 empleados activos. Actualmente hay 50.",
"validationErrors": []
}
Endpoints principales¶
Lista de los grupos de endpoints. Detalle exacto en Swagger.
Auth (/api/auth/*)¶
| Método | Path | Auth | Descripción |
|---|---|---|---|
| POST | /token |
Anonymous | Login → JWT + refresh token |
| POST | /refresh |
Anonymous | Renovar JWT |
| POST | /logout |
Bearer | Invalidar refresh token |
Rate limited (auth policy).
Tenants (/api/tenants/*) — solo SystemAdmin¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar tenants (con filtro opcional search, status) |
| GET | /{id} |
Detalle de un tenant |
| POST | / |
Crear tenant + primer admin |
| PUT | /{id} |
Editar tenant |
| POST | /{id}/status/{status} |
Cambiar status (0=Trial, 1=Active, 2=Suspended, 3=Cancelled) |
Plans (/api/plans/*) — solo SystemAdmin¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar planes |
| GET | /{id} |
Detalle |
| POST | / |
Crear plan |
| PUT | /{id} |
Editar plan |
| DELETE | /{id} |
Eliminar (solo si no hay tenants asignados) |
| POST | /assign/{tenantId} |
Asignar plan a tenant. Body: { planId: Guid } |
| GET | /usage/{tenantId} |
Snapshot de uso del tenant (empleados actuales/máx, ciclos) |
Employees (/api/employees/*) — HRManager / TenantAdmin¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar empleados (paginado, filtros: search, departmentId, status) |
| GET | /options |
Lista compacta para dropdowns |
| GET | /{id} |
Detalle |
| POST | / |
Crear empleado |
| PUT | /{id} |
Editar |
| DELETE | /{id} |
Soft-delete |
| POST | /{id}/photo |
Subir foto |
| POST | /{id}/invite |
Crear cuenta de acceso + enviar email con contraseña temporal |
| POST | /{id}/reset-password |
Generar nueva contraseña temporal |
| POST | /import-csv |
Importar masivo desde CSV (multipart, max 2 MB) |
Departments (/api/departments/*)¶
CRUD básico + listado tipo árbol.
Job Profiles (/api/job-profiles/*)¶
CRUD + versionado (POST /{id}/version clona como nueva versión).
Competencies (/api/competencies/*)¶
CRUD + import CSV (POST /import-csv).
Competency Categories (/api/competency-categories/*)¶
CRUD básico.
Skill Frameworks (/api/skill-frameworks/*)¶
CRUD + import JSON (formato genérico, tipo SFIA). Frameworks pueden ser globales (gestionados por SystemAdmin) o propios del tenant.
Evaluation Templates (/api/evaluation-templates/*)¶
CRUD + clonado para versionado.
Evaluation Cycles (/api/evaluation-cycles/*)¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar ciclos |
| GET | /{id} |
Detalle |
| POST | / |
Crear ciclo |
| PUT | /{id} |
Editar |
| POST | /{id}/status/{status} |
Cambiar status (0=Draft, 1=Open, 2=InProgress, 3=Closed, 4=Archived) |
| POST | /{id}/generate-evaluations |
Crear evaluaciones para todos los empleados activos |
| POST | /{id}/auto-assign-peers |
Auto-asignar pares a todos los subjects |
| POST | /{id}/auto-assign-direct-reports |
Auto-asignar reportes directos como evaluadores |
My Evaluations (/api/my-evaluations/*) — cualquier usuario¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar evaluaciones donde soy participant |
| GET | /{id} |
Detalle de la evaluación |
| POST | /{id}/respond |
Guardar respuestas (auto-save de borrador) |
| POST | /{id}/submit |
Enviar (validar + lockear) |
| POST | /{id}/acknowledge |
Acuso recibo de mis resultados (como subject) |
Evaluation Results (/api/evaluation-results/*)¶
Resultados agregados de un ciclo, exports a PDF.
Peer Assignments (/api/peer-assignments/*)¶
Asignar/quitar peers manualmente.
Email Triggers (/api/email-triggers/*)¶
| Método | Path | Descripción |
|---|---|---|
| POST | /cycle/{id}/notify-opened |
Disparar cycle-opened |
| POST | /cycle/{id}/deadline-reminder |
Disparar deadline-reminder (a quienes no enviaron) |
| POST | /cycle/{id}/results-published |
Disparar results-published a los subjects |
Email Templates (/api/email-templates/*)¶
CRUD del editor + send-test. Scope tenant o platform según rol.
Email Settings (/api/email-settings/*)¶
Configuración del proveedor de email del tenant.
Goals (/api/goals/*) y Key Results¶
CRUD + reportes de avance.
Development Plans (/api/development-plans/*) y Actions¶
CRUD + flujo de aprobación.
Career Paths (/api/career-paths/*)¶
CRUD de paths + readiness por empleado.
Gap Analysis (/api/gap-analysis/*)¶
Snapshot de brechas, análisis on-demand.
Gap Heatmap (/api/gap-heatmap/*)¶
Datos del heatmap + export Excel.
Nine Box (/api/nine-box/*)¶
Datos del 9-Box + export Excel.
Calibration (/api/calibration/*)¶
Sesiones de calibración (HR override de scores).
Dashboards (/api/dashboards/*)¶
Datos para dashboards (organizacional, plataforma, manager).
My Dashboard (/api/my-dashboard/*)¶
Datos del dashboard personal del empleado.
Tenant Settings (/api/tenant-settings/*)¶
Configuración del tenant (branding, locale).
Platform Settings (/api/platform-settings/*) — solo SystemAdmin¶
| Método | Path | Descripción |
|---|---|---|
| GET | /email |
Leer configuración de email de plataforma |
| PUT | /email |
Guardar configuración de email |
Users Admin (/api/users-admin/*) — TenantAdmin¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar usuarios del tenant |
| POST | / |
Crear usuario |
| PUT | /{id} |
Editar (incluye roles) |
| POST | /{id}/reset-password |
Generar contraseña temporal nueva |
| POST | /{id}/activate / /deactivate |
Toggle activo |
| POST | /{id}/unlock |
Desbloquear cuenta |
| GET | /{id}/sessions |
Listar tokens activos |
| POST | /{id}/revoke-all-sessions |
Revocar todas las sesiones |
Audit Logs (/api/audit-logs/*) — TenantAdmin / SystemAdmin¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Listar eventos (filtros: eventType, entityType, dateFrom, dateTo) |
| GET | /{id} |
Detalle |
Notifications (/api/notifications/*) — cualquier usuario¶
| Método | Path | Descripción |
|---|---|---|
| GET | / |
Mis notificaciones |
| GET | /unread-count |
Cantidad no leídas (para el badge) |
| POST | /{id}/mark-read |
Marcar como leída |
Files (/api/files/*)¶
Upload / download de archivos (fotos, evidencias).
My Profile (/api/my-profile/*)¶
Perfil del usuario actual: get, update, change avatar, change password.
Convenciones¶
Naming¶
- Snake-case en URLs (
/api/development-plansno/api/developmentPlans) - camelCase en JSON request/response (configurado en
Program.csconJsonNamingPolicy.CamelCase)
Paginación¶
Endpoints de listado típicamente:
GET /api/employees?page=1&pageSize=50&search=...&departmentId=...&status=...
page=1, pageSize=50. Max pageSize=200.
Response paginado:
{
"items": [...],
"totalCount": 1234,
"page": 1,
"pageSize": 50,
"totalPages": 25
}
IDs¶
Todos los IDs son Guid (UUID v4). Generados client o server-side.
Timestamps¶
Todos en UTC, formato ISO 8601 (2026-05-09T15:30:00Z).
Soft delete¶
Las entidades de negocio (Employee, JobProfile, etc.) usan soft-delete. DELETE /api/... marca IsDeleted=true, no borra físicamente.
Multi-tenancy en API¶
El tenant del request se resuelve por (en orden):
1. Claim tenant_id del JWT/cookie
2. Header X-Tenant: {slug} (para clientes confiables)
3. Subdominio del request (acme.eval360pro.com → tenant slug acme)
Si el tenant del usuario no matchea con el del subdominio, devuelve 401 con errorCode: TENANT_MISMATCH.
Rate limiting¶
Aplicado por IP del cliente:
- Política auth (login, refresh, password reset, 2FA challenge): 10 req/min/IP
- Default global: 200 req/min/IP
Si se supera: HTTP 429 con errorCode: RATE_LIMITED.
API pública v1 (/api/v1/*) — integradores y BI¶
Superficie de solo lectura para consumo externo, autenticada por API key
(header X-Api-Key, se crea en Integraciones). El tenant se resuelve desde la propia clave.
Es la que /swagger muestra en producción.
| Método | Path | Descripción |
|---|---|---|
| GET | /ping |
Verifica la clave; devuelve el tenant resuelto |
| GET | /employees |
Empleados (paginado: page, pageSize ≤ 200; filtros search, departmentId, status) |
| GET | /cycles |
Ciclos de evaluación |
| GET | /goals |
Objetivos / OKR con avance |
| GET | /pulse-surveys |
Encuestas de pulso (eNPS y fechas) |
| GET | /pulse-surveys/{id}/results |
Resultados de una encuesta (respeta el umbral de anonimato) |
| GET | /datasets/scores |
Plano: resultados por ciclo × colaborador (?cycleId= opcional) |
| GET | /datasets/gaps |
Plano: brechas por ciclo × colaborador × requisito (?cycleId= opcional) |
| GET | /datasets/nine-box |
Plano: 9-Box por ciclo × colaborador (?cycleId= opcional) |
Los datasets/* devuelven filas planas y denormalizadas, con las claves (cycleId,
employeeId) para modelar en estrella. Guía paso a paso para conectar Power BI (y similares):
Power BI y otras herramientas de BI.
Versionado¶
La API interna (/api/*, JWT/cookie) no está versionada: los endpoints se mantienen
estables y los cambios breaking se anuncian en el changelog.
La API pública para integradores vive bajo /api/v1/* y es la única que se expone en
producción. Versiones nuevas irían en /api/v2, manteniendo v1 mientras haya consumidores.