API Maslow (externa)
Maslow es la aplicación Flask de RR.HH. (empleados, organización, sincronización). Este documento cubre los endpoints pensados para ser llamados por sistemas externos y scripts (no los del navegador, que requieren sesión).
Repo fuente: maslow, branch main.
Cómo conectarse
- No hay host productivo committed. Maslow se corre en desarrollo en
http://127.0.0.1:5051(flask run --debug --port 5051). El host productivo (si existe) se provee externamente; usá<host>como la base de tu instancia. - Sin prefijo
/apiglobal. Los prefijos son por blueprint (/api/sync,/api/employees,/api/org,/api/users).
Autenticación
| Mecanismo | Header | Variables de entorno | Dónde |
|---|---|---|---|
| API Key | X-API-Key: <key> |
API_KEY |
/api/sync/* (menos /ids) |
| HTTP Basic | Authorization: Basic <base64(user:pass)> |
BASIC_AUTH_USERNAME / BASIC_AUTH_PASSWORD |
/api/sync/ids |
| Público | — | — | /api/employees, /api/org, /api/users, /health |
⚠️ Postura de seguridad a tener en cuenta: - Si
API_KEYno está seteada, los endpoints/api/sync/*quedan abiertos (modo dev). En producción debe configurarse. - SiBASIC_AUTH_USERNAMEyBASIC_AUTH_PASSWORDambos no están seteados,/api/sync/idsqueda abierto. - Los endpoints/api/employees,/api/orgy/api/usersno tienen autenticación (CRUD público). Probablemente pensados para el frontend, pero son llamables externamente — conviene protegerlos con un reverse proxy. -api_key_requiredcompara con!=(no es constante-tiempo).
En el resto del documento, <host> = la base de la instancia.
Healthcheck
GET <host>/health # público → {"status":"healthy"}
Sincronización — /api/sync
Superficie machine-to-machine para que sistemas externos lean datos de Maslow.
GET /api/sync/trabajadores [X-API-Key]
Empleados formateados para la tabla externa Trabajador. Ordenados por
updated_at DESC.
?include_inactive=false # bool, default false
&include_manager=false # bool, default false (incluye objeto jefe_directo)
&updated_since=2026-01-01T00:00:00 # ISO datetime, filtro incremental
400 {"error":"Invalid updated_since format. Use ISO format."} si la fecha no
es parseable. Por defecto excluye inactivos; jefe_directo sólo viene si
include_manager=true.
GET /api/sync/trabajadores/<rut> [X-API-Key]
Un empleado por RUT (acepta con/sin puntos y guion).
?include_manager=false
404 {"error":"Employee not found"}; 400 {"error":"Invalid RUT format"}.
GET /api/sync/trabajadores/krp [X-API-Key]
Empleados activos formateados para la integración KRP / logisticasbip:
{ rut, dv, first_name, paterno, materno, email } (email con fallback a
corporate_email).
GET /api/sync/centros-costo [X-API-Key]
Lista todos los centros de costo para mapeo:
{ count, centros_costo:[{ code, name, _maslow_id }] }.
GET /api/sync/ids [HTTP Basic]
RUT + IDs externos para cross-referenciar sincronizaciones.
?include_inactive=false # bool, default false
{ count, employees:[{ rut, id_toa, id_krp }] }. (Nota: usa Basic, no API Key.)
GET /api/sync/stats [X-API-Key]
Métricas de calidad de datos para planificar sincronización:
{ total_active, total_inactive, with_email, without_email,
with_cost_center, without_cost_center, duplicate_emails:[...] }.
Empleados — /api/employees [público]
CRUD completo de empleados (sin auth — ver advertencia arriba).
Listado y búsqueda
GET /api/employees?q=<texto>&cost_center_id=&position_id=&group_id=
&employment_type_id=&manager_id=&is_active=true
&include_relations=false
q busca ILIKE en first_name/paterno/materno/rut. Devuelve
{ employees:[...], count }.
Obtener uno
GET /api/employees/<int:id> # ?include_relations=true (default acá)
GET /api/employees/rut/<rut> # acepta 12.345.678-9; relations siempre incluidas
404 {"error":"Employee not found"}.
Crear
POST /api/employees
{ "rut": "12345678", "dv": "9", "first_name": "...", "paterno": "...",
"materno": "?", "gender": "?", "nationality": "?", "birth_date": "?",
"marital_status": "?", "hire_date": "?", "drivers_licence_expiry": "?",
"nubox_code": "?", "id_krp": "?", "id_toa": "?", "cost_center_id": "?",
"position_id": "?", "group_id": "?", "employment_type_id": "?",
"manager_id": "?" }
Requeridos: rut, dv, first_name, paterno. Fechas YYYY-MM-DD.
400 {"errors":[...]} (faltantes); 409 {"error":"Employee with RUT <rut> already exists"};
201 {"employee":{...}}.
Cambia PositionHistory / CostCenterHistory / ManagerAssignment cuando esos
FK cambian.
Actualizar / desactivar / reactivar
PUT /api/employees/<int:id> # cualquier campo; fechas YYYY-MM-DD
DELETE /api/employees/<int:id> # soft delete
POST /api/employees/<int:id>/reactivate
DELETE requiere body {"termination_date":"YYYY-MM-DD"} → cierra los
historiales abiertos; responde {"message":"Employee deactivated","employee":{...}}.
reactivate → 400 {"error":"Employee is already active"} si ya está activo.
Sub-recursos relacionados (todos PUT)
PUT /api/employees/<id>/contact # address, neighborhood, comuna, email, phone,
# corporate_email, corporate_phone, contract_address_city
PUT /api/employees/<id>/banking # bank_name, account_type, account_number
PUT /api/employees/<id>/benefits # pension_provider, health_provider, health_plan_amount, seremi_registration
PUT /api/employees/<id>/uniform # shirt_size, jacket_size, pants_size, shoe_size
Create-or-update (sólo setea claves que existen en el modelo). 404 si el
empleado no existe.
Organización — /api/org [público]
CRUD sobre cuatro entidades de referencia (todas sin auth). Patrón uniforme:
GET lista, GET /<id> uno, POST crea, PUT /<id> actualiza. Las listas
aceptan ?include_inactive=false.
Centros de costo — /api/org/cost-centers
POST /api/org/cost-centers { "code": "<req>", "name": "?" }
PUT /api/org/cost-centers/<id> { campos }
400 {"error":"Code is required"}; 409 {"error":"Cost center with code '<code>' already exists"}.
Cargos — /api/org/positions
POST { "title": "<req>", "description": "?" }
400 {"error":"Title is required"}; 409 si el título ya existe.
Grupos — /api/org/groups
POST { "code": "<req>", "name": "?" }
400 {"error":"Code is required"}; 409 si el código ya existe.
Tipos de contrato — /api/org/employment-types
POST { "code": "<req>", "name": "?", "description": "?" }
400 {"error":"Code is required"}; 409 si el código ya existe.
Usuarios — /api/users [público]
GET /api/users/ # lista todos → { "users":[ <user.to_dict()> ] } (ojo con el slash final)
GET /api/users/<int:id> # uno → { "user": <user.to_dict()> } ; 404 {"error":"User not found"}
Sin auth (ver advertencia).
Notas
- Esta doc cubre sólo la superficie externa/programática. Los endpoints de
export/import Excel (
/api/export/*,/api/import/*) requieren sesión de navegador (login en/auth/login→ cookie) y no se documentan aquí. - Login (sesión, no token):
POST /auth/logincon formularioemail+password→ setea cookie de sesión. No hay/auth/token,/auth/meni JWT. Roles:admin,rrhh,viewer. - El único endpoint AJAX de la app fuera de
/api/*esPATCH /empleados/<id>/id-toa(sesión + rolrrhh); también fuera de alcance.