{"openapi":"3.1.0","info":{"title":"FichMe API","version":"1.0.0","description":"API REST de FichMe para integrar el control horario con nóminas, ERPs, cuadros de mando y terminales. Autenticación con clave de API (cabecera `x-api-key` o `Authorization: Bearer`). JSON en camelCase, fechas de jornada `YYYY-MM-DD` en la zona horaria de la empresa, instantes ISO-8601 en UTC y errores `{ error: { code, message, param, requestId } }`.","contact":{"name":"Soporte de la API de FichMe","email":"api@fichme.com","url":"https://fichme.com/developers"}},"servers":[{"url":"https://api.fichme.com"}],"security":[{"ApiKeyHeader":[]},{"BearerAuth":[]}],"tags":[{"name":"Clave","description":"Introspección de la clave y de la empresa."},{"name":"Empresa","description":"Datos de la empresa y centros de trabajo."},{"name":"Empleados","description":"Plantilla. Los datos fiscales (DNI, nº S. S.) solo con employees:read_pii."},{"name":"Fichajes","description":"Pulsaciones crudas, jornadas calculadas y registro de fichajes en tiempo real."},{"name":"Correcciones","description":"Solicitudes de corrección de fichajes: la única vía para tocar el pasado."},{"name":"Ausencias","description":"Tipos, solicitudes y saldos de ausencias (vacaciones, permisos, bajas...). Las ausencias de salud (bajas, consultas médicas) y los motivos escritos son datos sensibles: solo con employees:read_pii."},{"name":"Balance","description":"Horas previstas frente a trabajadas."},{"name":"Turnos","description":"Turnos, asignaciones y festivos."},{"name":"Exportaciones","description":"Informes asíncronos (CSV, XLSX, PDF) para periodos largos."},{"name":"Webhooks","description":"Avisos firmados cuando algo cambia en la empresa (planes Business y Enterprise). Cómo recibirlos y verificar la firma: guía «Recibir webhooks»."}],"paths":{"/v1/me":{"get":{"tags":["Clave"],"summary":"Comprobar la clave","description":"El «hola mundo» de la API: a qué empresa pertenece la clave, qué scopes tiene, cuándo caduca y qué límites le aplican. No requiere ningún scope.\n\n**Scope:** ninguno","operationId":"getMe","responses":{"200":{"description":"La clave y su empresa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"object":"me","apiKey":{"id":"cm1key9p0008qx5b3c7n2m4wl","name":"Gestoría Pérez","prefix":"fm_live_k7m2p5x4q3ab","scopes":["company:read","employees:read","clock:read"],"expiresAt":"2027-09-15T10:00:00.000Z"},"company":{"id":1042,"name":"Construcciones Ebro","slug":"construcciones-ebro","timezone":"Europe/Madrid"},"plan":{"name":"Business","webhooks":true},"rateLimit":{"perMinute":120,"perDay":50000,"maxConcurrentHeavy":1},"apiVersion":"v1","serverTime":"2026-09-15T10:04:12.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}}}},"/v1/company":{"get":{"tags":["Empresa"],"summary":"Datos de la empresa","description":"La empresa de la clave y los ajustes que hacen falta para interpretar el resto de datos. Solo lectura: los ajustes se cambian en el panel.\n\n**Scope:** `company:read`","operationId":"getCompany","x-scope":"company:read","responses":{"200":{"description":"La empresa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"},"example":{"object":"company","id":1042,"name":"Construcciones Ebro","legalName":"Construcciones Ebro, S.L.","taxId":"B50123456","slug":"construcciones-ebro","address":"Calle del Coso 42","city":"Zaragoza","province":"Zaragoza","postalCode":"50004","country":"España","timezone":"Europe/Madrid","settings":{"workingDays":[1,2,3,4,5],"lateArrivalThreshold":10,"earlyDepartureThreshold":10,"mandatoryBreakMinutes":30,"maxShiftHours":16,"apiClockingEnabled":true,"hourBankEnabled":true,"geolocationEnabled":false}}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}}}},"/v1/locations":{"get":{"tags":["Empresa"],"summary":"Centros de trabajo","description":"Los centros de la empresa (sin paginar: es un catálogo pequeño), el principal primero: los mismos donde se puede fichar desde la web. Además de los propios, salen los de sistema que siguen en uso (`isSystem: true`): «Teletrabajo» si la empresa permite teletrabajo, y «Principal» solo mientras no tenga centros propios. Los de sistema no se asignan a empleados.\n\n**Scope:** `company:read`","operationId":"getLocations","x-scope":"company:read","parameters":[{"name":"isActive","in":"query","required":false,"description":"Filtrar por centros activos o inactivos.","schema":{"type":"string"},"example":true}],"responses":{"200":{"description":"Lista de centros","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Location"}}}}]},"example":{"object":"list","data":[{"object":"location","id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza","code":"ZGZ","address":"Calle del Coso 42","city":"Zaragoza","province":"Zaragoza","timezone":null,"isActive":true,"isPrimary":true,"isSystem":false,"geofence":{"enabled":true,"radiusMeters":150,"latitude":41.6523,"longitude":-0.8773},"createdAt":"2025-02-03T09:12:44.000Z","updatedAt":"2026-06-11T15:30:02.000Z"}],"page":1,"limit":1,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}}}},"/v1/employees":{"get":{"tags":["Empleados"],"summary":"Lista de empleados","description":"Plantilla de la empresa, ordenada por apellidos. Por defecto solo los activos. Con `updatedSince` devuelve los cambiados desde ese instante (bajas incluidas, con `deleted: true`) y pagina por cursor.\n\n**Scope:** `employees:read`","operationId":"getEmployees","x-scope":"employees:read","parameters":[{"name":"status","in":"query","required":false,"description":"Estado operativo. Por defecto ACTIVE.","schema":{"default":"ACTIVE","type":"string","enum":["ACTIVE","INACTIVE","ALL"]},"example":"ACTIVE"},{"name":"locationId","in":"query","required":false,"description":"Centro de trabajo (principal o de pertenencia).","schema":{"type":"string","minLength":1,"maxLength":64}},{"name":"search","in":"query","required":false,"description":"Texto en el nombre o el email.","schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"includeDeleted","in":"query","required":false,"description":"Incluir empleados dados de baja lógica.","schema":{"type":"string"}},{"name":"updatedSince","in":"query","required":false,"description":"Sincronización incremental: solo los modificados desde este instante (ver guía).","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},{"name":"cursor","in":"query","required":false,"description":"Cursor devuelto en nextCursor (solo con updatedSince).","schema":{"type":"string","maxLength":200}},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Resultados por página (máx. 500).","schema":{"default":50,"type":"integer","minimum":1,"maximum":500},"example":100}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}}}]},"example":{"object":"list","data":[{"object":"employee","id":4821,"firstName":"Ana","lastName":"García López","name":"Ana García López","email":"ana.garcia@example.com","role":"EMPLOYEE","status":"ACTIVE","activationStatus":"ACTIVATED","jobTitle":"Técnica de obra","department":"Producción","hireDate":"2024-03-01","seniorityDate":"2024-03-01","contract":{"type":"FULL_TIME","weeklyHours":40,"annualHours":1776,"isNightWorker":false},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"locations":[{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza","isPrimary":true}],"clockingPolicy":{"exempt":false,"web":null,"app":true,"terminal":null,"requireGeolocation":null},"identity":{"taxId":"12345678Z","socialSecurityNumber":"281234567840","phone":"+34 600 123 456"},"createdAt":"2024-02-20T10:05:13.000Z","updatedAt":"2026-09-01T08:14:55.000Z","deletedAt":null}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":400,"code":"page_out_of_range","when":"page × limit supera 50.000. Para volcados completos usa updatedSince."},{"status":400,"code":"invalid_request","when":"cursor sin updatedSince, o un cursor manipulado o de otra clave: vuelve a empezar desde updatedSince."}]},"post":{"tags":["Empleados"],"summary":"Alta de empleado","description":"Crea un empleado (rol EMPLOYEE) con las mismas validaciones que el panel: límite de empleados del plan (422 `seat_limit_reached`), email y DNI únicos (409 `already_exists` con `existingId`). Si tiene email y `sendWelcomeEmail` es true, recibe el correo de bienvenida con su acceso.\n\n**Scope:** `employees:write`","operationId":"postEmployees","x-scope":"employees:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"description":"Nombre.","type":"string","minLength":1,"maxLength":100},"lastName":{"description":"Apellidos.","type":"string","minLength":1,"maxLength":150},"email":{"description":"Obligatorio si no se envía dni.","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE. Obligatorio si no se envía email. Enviarlo requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"socialSecurityNumber":{"description":"Nº de afiliación a la Seguridad Social.","type":"string","minLength":5,"maxLength":30},"phone":{"description":"Teléfono.","type":"string","minLength":3,"maxLength":30},"jobTitle":{"description":"Puesto.","type":"string","minLength":1,"maxLength":120},"department":{"description":"Departamento.","type":"string","minLength":1,"maxLength":120},"hireDate":{"description":"Fecha de alta (YYYY-MM-DD).","type":"string"},"seniorityDate":{"description":"Fecha de antigüedad (YYYY-MM-DD), si no coincide con el alta.","type":"string"},"locationId":{"description":"Centro principal.","type":"string","minLength":1,"maxLength":64},"locationIds":{"description":"Centros adicionales de pertenencia.","maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":64}},"shiftId":{"description":"Turno fijo a asignar desde hoy.","type":"string","minLength":1,"maxLength":64},"contract":{"description":"Datos del contrato.","type":"object","properties":{"type":{"description":"Tipo de contrato.","anyOf":[{"type":"string","enum":["FULL_TIME","PART_TIME","TEMPORARY"]},{"type":"null"}]},"weeklyHours":{"description":"Horas semanales contratadas.","anyOf":[{"type":"number","minimum":0,"maximum":80},{"type":"null"}]},"annualHours":{"description":"Horas anuales contratadas.","anyOf":[{"type":"number","minimum":0,"maximum":4000},{"type":"null"}]},"isNightWorker":{"description":"Trabajador nocturno (art. 36 ET).","type":"boolean"}},"additionalProperties":false},"sendWelcomeEmail":{"description":"Enviar el correo de bienvenida con el acceso (requiere email).","default":true,"type":"boolean"}},"required":["firstName"],"additionalProperties":false},"example":{"firstName":"Ana","lastName":"García López","email":"ana.garcia@example.com","jobTitle":"Técnica de obra","department":"Producción","hireDate":"2026-09-01","locationId":"cm1loczgz0001qx8f2k9d7h3a","contract":{"type":"FULL_TIME","weeklyHours":40},"sendWelcomeEmail":true}}}},"responses":{"201":{"description":"Empleado creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Employee"},"example":{"object":"employee","id":4821,"firstName":"Ana","lastName":"García López","name":"Ana García López","email":"ana.garcia@example.com","role":"EMPLOYEE","status":"ACTIVE","activationStatus":"PENDING_ACTIVATION","jobTitle":"Técnica de obra","department":"Producción","hireDate":"2026-09-01","seniorityDate":"2026-09-01","contract":{"type":"FULL_TIME","weeklyHours":40,"annualHours":1776,"isNightWorker":false},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"locations":[{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza","isPrimary":true}],"clockingPolicy":{"exempt":false,"web":null,"app":true,"terminal":null,"requireGeolocation":null},"identity":{"taxId":"12345678Z","socialSecurityNumber":"281234567840","phone":"+34 600 123 456"},"createdAt":"2024-02-20T10:05:13.000Z","updatedAt":"2026-09-01T08:14:55.000Z","deletedAt":null}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"already_exists","when":"Ya hay un empleado con ese email o DNI: `existingId` dice cuál (actualízalo con PATCH)."},{"status":422,"code":"seat_limit_reached","when":"La empresa ha llegado al máximo de empleados de su plan."},{"status":404,"code":"not_found","when":"El centro (`locationId`/`locationIds`) o el turno (`shiftId`) no existen o están inactivos."},{"status":422,"code":"validation_failed","when":"Algún centro es de sistema («Principal» o «Teletrabajo», `isSystem: true`): no se asignan a empleados."},{"status":403,"code":"insufficient_scope","when":"Enviar `dni` sin el scope employees:read_pii."}]}},"/v1/employees/{id}":{"get":{"tags":["Empleados"],"summary":"Un empleado","description":"Por id de FichMe o, si tu sistema no lo conoce, por `email:ana@example.com` o `dni:12345678Z` (este último requiere employees:read_pii). Devuelve también las bajas, con `deletedAt`.\n\n**Scope:** `employees:read`","operationId":"getEmployeesId","x-scope":"employees:read","parameters":[{"name":"id","in":"path","required":true,"description":"Id numérico de FichMe, o `email:ana@example.com`, o `dni:12345678Z` (este último requiere employees:read_pii).","schema":{"type":"string","minLength":1,"maxLength":260},"example":"email:ana.garcia@example.com"}],"responses":{"200":{"description":"El empleado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Employee"},"example":{"object":"employee","id":4821,"firstName":"Ana","lastName":"García López","name":"Ana García López","email":"ana.garcia@example.com","role":"EMPLOYEE","status":"ACTIVE","activationStatus":"ACTIVATED","jobTitle":"Técnica de obra","department":"Producción","hireDate":"2024-03-01","seniorityDate":"2024-03-01","contract":{"type":"FULL_TIME","weeklyHours":40,"annualHours":1776,"isNightWorker":false},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"locations":[{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza","isPrimary":true}],"clockingPolicy":{"exempt":false,"web":null,"app":true,"terminal":null,"requireGeolocation":null},"identity":{"taxId":"12345678Z","socialSecurityNumber":"281234567840","phone":"+34 600 123 456"},"createdAt":"2024-02-20T10:05:13.000Z","updatedAt":"2026-09-01T08:14:55.000Z","deletedAt":null}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No hay ningún empleado con ese id, email o DNI en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Buscar por `dni:` sin el scope employees:read_pii."}]},"patch":{"tags":["Empleados"],"summary":"Editar empleado","description":"Actualiza solo los campos enviados. No cambia el rol ni credenciales, y no toca cuentas de administrador (403 `admin_protected`). Reactivar (`status: ACTIVE`) cuenta contra el límite de empleados del plan.\n\n**Scope:** `employees:write`","operationId":"patchEmployeesId","x-scope":"employees:write","parameters":[{"name":"id","in":"path","required":true,"description":"Id numérico de FichMe, o `email:ana@example.com`, o `dni:12345678Z` (este último requiere employees:read_pii).","schema":{"type":"string","minLength":1,"maxLength":260},"example":4821}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"description":"Nombre.","type":"string","minLength":1,"maxLength":100},"lastName":{"description":"Apellidos (null los borra).","anyOf":[{"type":"string","minLength":1,"maxLength":150},{"type":"null"}]},"email":{"description":"Email (también es su usuario de acceso).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE. Cambiarlo requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"socialSecurityNumber":{"description":"Nº de afiliación a la Seguridad Social.","anyOf":[{"type":"string","minLength":5,"maxLength":30},{"type":"null"}]},"phone":{"description":"Teléfono.","anyOf":[{"type":"string","minLength":3,"maxLength":30},{"type":"null"}]},"jobTitle":{"description":"Puesto.","anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"department":{"description":"Departamento.","anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"hireDate":{"description":"Fecha de alta (YYYY-MM-DD).","anyOf":[{"type":"string"},{"type":"null"}]},"seniorityDate":{"description":"Fecha de antigüedad (YYYY-MM-DD).","anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"description":"Cambia el centro principal y conserva los demás.","type":"string","minLength":1,"maxLength":64},"locationIds":{"description":"Conjunto COMPLETO de centros de pertenencia ([] = ninguno).","maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":64}},"contract":{"description":"Datos del contrato (solo los campos enviados).","type":"object","properties":{"type":{"description":"Tipo de contrato.","anyOf":[{"type":"string","enum":["FULL_TIME","PART_TIME","TEMPORARY"]},{"type":"null"}]},"weeklyHours":{"description":"Horas semanales contratadas.","anyOf":[{"type":"number","minimum":0,"maximum":80},{"type":"null"}]},"annualHours":{"description":"Horas anuales contratadas.","anyOf":[{"type":"number","minimum":0,"maximum":4000},{"type":"null"}]},"isNightWorker":{"description":"Trabajador nocturno (art. 36 ET).","type":"boolean"}},"additionalProperties":false},"status":{"description":"Reactivar cuenta contra el límite de empleados del plan.","type":"string","enum":["ACTIVE","INACTIVE"]}},"additionalProperties":false},"example":{"jobTitle":"Jefa de obra","department":"Producción"}}}},"responses":{"200":{"description":"Empleado actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Employee"},"example":{"object":"employee","id":4821,"firstName":"Ana","lastName":"García López","name":"Ana García López","email":"ana.garcia@example.com","role":"EMPLOYEE","status":"ACTIVE","activationStatus":"ACTIVATED","jobTitle":"Jefa de obra","department":"Producción","hireDate":"2024-03-01","seniorityDate":"2024-03-01","contract":{"type":"FULL_TIME","weeklyHours":40,"annualHours":1776,"isNightWorker":false},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"locations":[{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza","isPrimary":true}],"clockingPolicy":{"exempt":false,"web":null,"app":true,"terminal":null,"requireGeolocation":null},"identity":{"taxId":"12345678Z","socialSecurityNumber":"281234567840","phone":"+34 600 123 456"},"createdAt":"2024-02-20T10:05:13.000Z","updatedAt":"2026-09-01T08:14:55.000Z","deletedAt":null}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"admin_protected","when":"Es una cuenta de administrador: solo se modifica desde el panel."},{"status":409,"code":"already_exists","when":"Otro empleado ya tiene ese email o DNI (`existingId`)."},{"status":422,"code":"seat_limit_reached","when":"Reactivar (`status: ACTIVE`) superaría el máximo de empleados del plan."},{"status":404,"code":"not_found","when":"El empleado o alguno de los centros no existen."},{"status":422,"code":"validation_failed","when":"Algún centro es de sistema («Principal» o «Teletrabajo», `isSystem: true`): no se asignan a empleados."},{"status":403,"code":"insufficient_scope","when":"Usar `dni:` en la ruta o cambiar el `dni` sin el scope employees:read_pii."}]}},"/v1/employees/{id}/deactivate":{"post":{"tags":["Empleados"],"summary":"Desactivar empleado","description":"Baja operativa: el empleado pasa a INACTIVE, deja de poder fichar y libera su plaza del plan. Sus fichajes y datos legales se conservan. Es idempotente y reversible con `PATCH { \"status\": \"ACTIVE\" }`. Nunca hay borrado físico por API.\n\n**Scope:** `employees:write`","operationId":"postEmployeesIdDeactivate","x-scope":"employees:write","parameters":[{"name":"id","in":"path","required":true,"description":"Id numérico de FichMe, o `email:ana@example.com`, o `dni:12345678Z` (este último requiere employees:read_pii).","schema":{"type":"string","minLength":1,"maxLength":260},"example":4821}],"responses":{"200":{"description":"Empleado desactivado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Employee"},"example":{"object":"employee","id":4821,"firstName":"Ana","lastName":"García López","name":"Ana García López","email":"ana.garcia@example.com","role":"EMPLOYEE","status":"INACTIVE","activationStatus":"ACTIVATED","jobTitle":"Técnica de obra","department":"Producción","hireDate":"2024-03-01","seniorityDate":"2024-03-01","contract":{"type":"FULL_TIME","weeklyHours":40,"annualHours":1776,"isNightWorker":false},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"locations":[{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza","isPrimary":true}],"clockingPolicy":{"exempt":false,"web":null,"app":true,"terminal":null,"requireGeolocation":null},"identity":{"taxId":"12345678Z","socialSecurityNumber":"281234567840","phone":"+34 600 123 456"},"createdAt":"2024-02-20T10:05:13.000Z","updatedAt":"2026-09-01T08:14:55.000Z","deletedAt":null}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"admin_protected","when":"Es una cuenta de administrador: solo se desactiva desde el panel."},{"status":404,"code":"not_found","when":"No existe en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Usar `dni:` en la ruta sin el scope employees:read_pii."}]}},"/v1/clock-entries":{"get":{"tags":["Fichajes"],"summary":"Fichajes crudos","description":"Cada resultado es una pulsación (IN, OUT, BREAK_START, BREAK_END), ordenadas por instante. `from`/`to` filtran por la fecha de JORNADA (`shiftDate`), no por el instante UTC: así un turno de noche devuelve su entrada y su salida juntas. Máximo 93 días; para más, `POST /v1/exports`. Una pausa se registra como OUT + BREAK_START y su vuelta como BREAK_END + IN, con el mismo instante. Para jornadas ya emparejadas y con horas calculadas usa `GET /v1/work-sessions`.\n\n**Scope:** `clock:read`","operationId":"getClockEntries","x-scope":"clock:read","parameters":[{"name":"from","in":"query","required":false,"description":"Primer día de JORNADA (shiftDate), inclusive.","schema":{"type":"string"},"example":"2026-09-01"},{"name":"to","in":"query","required":false,"description":"Último día de jornada, inclusive. Máximo 93 días.","schema":{"type":"string"},"example":"2026-09-30"},{"name":"timestampFrom","in":"query","required":false,"description":"Alternativa a from/to: instante UTC inicial.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},{"name":"timestampTo","in":"query","required":false,"description":"Alternativa a from/to: instante UTC final.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},{"name":"updatedSince","in":"query","required":false,"description":"Sincronización incremental (excluye los otros filtros de fecha).","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},{"name":"cursor","in":"query","required":false,"description":"Cursor de nextCursor (solo con updatedSince).","schema":{"type":"string","maxLength":200}},{"name":"employeeId","in":"query","required":false,"description":"Solo los fichajes de este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"name":"type","in":"query","required":false,"description":"Solo este tipo de pulsación.","schema":{"type":"string","enum":["IN","OUT","BREAK_START","BREAK_END"]}},{"name":"method","in":"query","required":false,"description":"Solo los registrados por este canal.","schema":{"type":"string","enum":["WEB","APP","QR","KIOSK","SLACK","WHATSAPP","API"]}},{"name":"locationId","in":"query","required":false,"description":"Solo los registrados en este centro.","schema":{"type":"string","minLength":1,"maxLength":64}},{"name":"includeDeleted","in":"query","required":false,"description":"Incluir fichajes eliminados (con deletedAt).","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Resultados por página (máx. 500).","schema":{"default":50,"type":"integer","minimum":1,"maximum":500},"example":500}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClockEntry"}}}}]},"example":{"object":"list","data":[{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"APP","source":"MOBILE","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":400,"code":"invalid_date_range","when":"Falta from o to (van juntos), o from es posterior a to."},{"status":400,"code":"date_range_too_large","when":"Más de 93 días: pide el periodo por partes o usa POST /v1/exports."},{"status":400,"code":"conflicting_filters","when":"Mezclas from/to, timestampFrom/timestampTo y updatedSince: usa uno solo."}]}},"/v1/clock-entries/{id}":{"get":{"tags":["Fichajes"],"summary":"Un fichaje","description":"Un fichaje por su id (el que devuelven los listados, las jornadas y los webhooks).\n\n**Scope:** `clock:read`","operationId":"getClockEntriesId","x-scope":"clock:read","parameters":[{"name":"id","in":"path","required":true,"description":"Id numérico.","schema":{"type":"string","pattern":"^\\d{1,10}$"},"example":918273}],"responses":{"200":{"description":"El fichaje","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockEntry"},"example":{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"APP","source":"MOBILE","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/work-sessions":{"get":{"tags":["Fichajes"],"summary":"Jornadas calculadas","description":"Una fila por empleado y día del periodo, con las pulsaciones ya emparejadas en tramos y las horas calculadas con el mismo motor que el Balance de horas del panel: trabajado, previsto, balance, pausas retribuidas y descontadas, y las ausencias aprobadas del día. Es lo que necesita una nómina.\n\nLa paginación va por EMPLEADOS: `limit` es el número de empleados por página y `total` el de empleados (sin bajas ni exentos de fichar). Cada página trae todos los días de sus empleados.\n\n**Scope:** `clock:read`\n\n**Endpoint pesado:** como mucho 1 petición simultánea por clave.","operationId":"getWorkSessions","x-scope":"clock:read","parameters":[{"name":"from","in":"query","required":true,"description":"Primer día de jornada (inclusive).","schema":{"type":"string"},"example":"2026-09-01"},{"name":"to","in":"query","required":true,"description":"Último día de jornada (inclusive). Máximo 93 días.","schema":{"type":"string"},"example":"2026-09-30"},{"name":"employeeId","in":"query","required":false,"description":"Solo este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"name":"locationId","in":"query","required":false,"description":"Empleados de este centro (principal o de pertenencia).","schema":{"type":"string","minLength":1,"maxLength":64}},{"name":"status","in":"query","required":false,"description":"Estado del empleado.","schema":{"default":"ALL","type":"string","enum":["ACTIVE","INACTIVE","ALL"]}},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"EMPLEADOS por página (máx. 100): cada uno trae todos sus días del periodo.","schema":{"default":25,"type":"integer","minimum":1,"maximum":100},"example":50}],"responses":{"200":{"description":"Lista paginada por empleados","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkSession"}}}}]},"example":{"object":"list","data":[{"object":"workSession","employeeId":4821,"shiftDate":"2026-09-15","dayType":"WORKING","status":"COMPLETE","scheduleSource":"SHIFT","firstIn":"2026-09-15T06:58:31.000Z","lastOut":"2026-09-15T15:02:10.000Z","segments":[{"in":"2026-09-15T06:58:31.000Z","out":"2026-09-15T11:00:02.000Z","entryIds":[918273,918280],"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"}},{"in":"2026-09-15T11:30:15.000Z","out":"2026-09-15T15:02:10.000Z","entryIds":[918283,918290],"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"}}],"breaks":[{"start":"2026-09-15T11:00:02.000Z","end":"2026-09-15T11:30:15.000Z","entryIds":[918281,918282]}],"workedMinutes":453,"workedTime":"07:33","clockedMinutes":453,"breakMinutes":30,"paidBreakMinutes":0,"autoDeductedBreakMinutes":0,"assignedMinutes":450,"assignedTime":"07:30","balanceMinutes":3,"balanceTime":"00:03","leaves":[],"isModified":false,"requiresCorrection":false,"hasOpenSegment":false,"engine":"hours_balance_v1"}],"page":1,"limit":25,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":400,"code":"invalid_date_range","when":"Falta from o to, o from es posterior a to."},{"status":400,"code":"date_range_too_large","when":"Más de 93 días: pide el periodo por partes o usa POST /v1/exports."},{"status":429,"code":"too_many_concurrent_requests","when":"Supera el máximo de 1 petición simultánea por clave en los endpoints pesados: espera a que terminen."}]}},"/v1/clock":{"post":{"tags":["Fichajes"],"summary":"Fichar (interruptor)","description":"Como el botón de fichar: si el empleado no está trabajando registra una ENTRADA; si lo está, una SALIDA; si está en pausa, la cierra y reanuda la jornada. La hora es la del servidor. Requiere que la empresa haya activado el fichaje por API. Envía `Idempotency-Key` para poder reintentar sin duplicar.\n\n**Scope:** `clock:write`","operationId":"postClock","x-scope":"clock:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Clave única por intento lógico (≤ 128 caracteres). Un reintento con la misma clave devuelve el mismo fichaje, nunca uno duplicado.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"locationId":{"description":"Centro de trabajo. Si se omite en una salida, hereda el de la entrada.","type":"string","minLength":1,"maxLength":64},"deviceTimestamp":{"description":"Hora del dispositivo, como evidencia. La hora del fichaje es la del servidor; más de ±5 min de diferencia → 422.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},"additionalProperties":false},"example":{"employeeId":4821}}}},"responses":{"201":{"description":"Fichaje registrado (200 si es un reintento)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockAction"},"example":{"object":"clockAction","action":"IN","state":"working","entry":{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null},"entries":[{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null}],"idempotentReplay":false}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"api_clocking_disabled","when":"La empresa no ha activado el fichaje por API (Ajustes → API)."},{"status":403,"code":"employee_inactive","when":"El empleado está INACTIVE."},{"status":403,"code":"clocking_blocked_for_employee","when":"El empleado está exento de fichar."},{"status":404,"code":"not_found","when":"No hay ningún empleado con ese employeeId, email o DNI en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Identificar al empleado por `dni` sin el scope employees:read_pii."},{"status":409,"code":"idempotency_key_reused","when":"Ese Idempotency-Key ya se usó para otro fichaje: genera uno nuevo por intento."},{"status":422,"code":"timestamp_out_of_window","when":"deviceTimestamp difiere más de 5 min de la hora del servidor. El pasado va por correcciones."},{"status":409,"code":"clock_state_conflict","when":"El estado cambió a la vez desde otro dispositivo: vuelve a leer el estado y reintenta."}]}},"/v1/clock/in":{"post":{"tags":["Fichajes"],"summary":"Fichar entrada","description":"Entrada explícita, para terminales que saben qué botón se pulsó. 409 `clock_state_conflict` con `state: ALREADY_CLOCKED_IN` si ya tiene una entrada activa (aunque sea de un día anterior que aún no se ha cerrado) o `BREAK_ALREADY_OPEN` si está en pausa. El estado se comprueba en el momento de escribir: dos peticiones simultáneas no crean dos entradas.\n\n**Scope:** `clock:write`","operationId":"postClockIn","x-scope":"clock:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Clave única por intento lógico (≤ 128 caracteres). Un reintento con la misma clave devuelve el mismo fichaje, nunca uno duplicado.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"locationId":{"description":"Centro de trabajo. Si se omite en una salida, hereda el de la entrada.","type":"string","minLength":1,"maxLength":64},"deviceTimestamp":{"description":"Hora del dispositivo, como evidencia. La hora del fichaje es la del servidor; más de ±5 min de diferencia → 422.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},"additionalProperties":false},"example":{"employeeId":4821,"locationId":"cm1loczgz0001qx8f2k9d7h3a"}}}},"responses":{"201":{"description":"Entrada registrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockAction"},"example":{"object":"clockAction","action":"IN","state":"working","entry":{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null},"entries":[{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null}],"idempotentReplay":false}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"clock_state_conflict","when":"`state: ALREADY_CLOCKED_IN` (ya está dentro) o `BREAK_ALREADY_OPEN` (está en pausa)."},{"status":403,"code":"api_clocking_disabled","when":"La empresa no ha activado el fichaje por API (Ajustes → API)."},{"status":403,"code":"employee_inactive","when":"El empleado está INACTIVE."},{"status":403,"code":"clocking_blocked_for_employee","when":"El empleado está exento de fichar."},{"status":404,"code":"not_found","when":"No hay ningún empleado con ese employeeId, email o DNI en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Identificar al empleado por `dni` sin el scope employees:read_pii."},{"status":409,"code":"idempotency_key_reused","when":"Ese Idempotency-Key ya se usó para otro fichaje: genera uno nuevo por intento."},{"status":422,"code":"timestamp_out_of_window","when":"deviceTimestamp difiere más de 5 min de la hora del servidor. El pasado va por correcciones."}]}},"/v1/clock/out":{"post":{"tags":["Fichajes"],"summary":"Fichar salida","description":"Salida explícita: cierra la entrada activa y hereda su jornada (`shiftDate`) y su centro si no se indica otro. 409 `clock_state_conflict` con `state: NO_ACTIVE_IN` si no hay entrada activa o `BREAK_ALREADY_OPEN` si hay una pausa abierta (ciérrala antes).\n\n**Scope:** `clock:write`","operationId":"postClockOut","x-scope":"clock:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Clave única por intento lógico (≤ 128 caracteres). Un reintento con la misma clave devuelve el mismo fichaje, nunca uno duplicado.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"locationId":{"description":"Centro de trabajo. Si se omite en una salida, hereda el de la entrada.","type":"string","minLength":1,"maxLength":64},"deviceTimestamp":{"description":"Hora del dispositivo, como evidencia. La hora del fichaje es la del servidor; más de ±5 min de diferencia → 422.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},"additionalProperties":false},"example":{"employeeId":4821}}}},"responses":{"201":{"description":"Salida registrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockAction"},"example":{"object":"clockAction","action":"OUT","state":"off","entry":{"object":"clockEntry","id":918290,"employeeId":4821,"type":"OUT","timestamp":"2026-09-15T15:02:10.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":"on-time","minutesEarly":null},"createdAt":"2026-09-15T15:02:10.000Z","updatedAt":"2026-09-15T15:02:10.000Z","deletedAt":null},"entries":[{"object":"clockEntry","id":918290,"employeeId":4821,"type":"OUT","timestamp":"2026-09-15T15:02:10.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":"on-time","minutesEarly":null},"createdAt":"2026-09-15T15:02:10.000Z","updatedAt":"2026-09-15T15:02:10.000Z","deletedAt":null}],"idempotentReplay":false}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"clock_state_conflict","when":"`state: NO_ACTIVE_IN` (no tiene una entrada abierta) o `BREAK_ALREADY_OPEN` (está en pausa)."},{"status":403,"code":"api_clocking_disabled","when":"La empresa no ha activado el fichaje por API (Ajustes → API)."},{"status":403,"code":"employee_inactive","when":"El empleado está INACTIVE."},{"status":403,"code":"clocking_blocked_for_employee","when":"El empleado está exento de fichar."},{"status":404,"code":"not_found","when":"No hay ningún empleado con ese employeeId, email o DNI en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Identificar al empleado por `dni` sin el scope employees:read_pii."},{"status":409,"code":"idempotency_key_reused","when":"Ese Idempotency-Key ya se usó para otro fichaje: genera uno nuevo por intento."},{"status":422,"code":"timestamp_out_of_window","when":"deviceTimestamp difiere más de 5 min de la hora del servidor. El pasado va por correcciones."}]}},"/v1/clock/break/start":{"post":{"tags":["Fichajes"],"summary":"Iniciar pausa","description":"Registra la salida y el inicio de pausa en el mismo instante (dos fichajes, de forma atómica). 409 si no está trabajando. El empleado se puede indicar por email o DNI si tu sistema no conoce su id.\n\n**Scope:** `clock:write`","operationId":"postClockBreakStart","x-scope":"clock:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Clave única por intento lógico (≤ 128 caracteres). Un reintento con la misma clave devuelve el mismo fichaje, nunca uno duplicado.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"locationId":{"description":"Centro de trabajo. Si se omite en una salida, hereda el de la entrada.","type":"string","minLength":1,"maxLength":64},"deviceTimestamp":{"description":"Hora del dispositivo, como evidencia. La hora del fichaje es la del servidor; más de ±5 min de diferencia → 422.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},"additionalProperties":false},"example":{"email":"ana.garcia@example.com"}}}},"responses":{"201":{"description":"Pausa iniciada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockAction"},"example":{"object":"clockAction","action":"BREAK_START","state":"on_break","entry":{"object":"clockEntry","id":918281,"employeeId":4821,"type":"BREAK_START","timestamp":"2026-09-15T11:00:02.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T11:00:02.000Z","updatedAt":"2026-09-15T11:00:02.000Z","deletedAt":null},"entries":[{"object":"clockEntry","id":918280,"employeeId":4821,"type":"OUT","timestamp":"2026-09-15T11:00:02.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T11:00:02.000Z","updatedAt":"2026-09-15T11:00:02.000Z","deletedAt":null},{"object":"clockEntry","id":918281,"employeeId":4821,"type":"BREAK_START","timestamp":"2026-09-15T11:00:02.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T11:00:02.000Z","updatedAt":"2026-09-15T11:00:02.000Z","deletedAt":null}],"idempotentReplay":false}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"clock_state_conflict","when":"`state: NO_ACTIVE_IN` (no está trabajando) o `BREAK_ALREADY_OPEN` (ya está en pausa)."},{"status":403,"code":"api_clocking_disabled","when":"La empresa no ha activado el fichaje por API (Ajustes → API)."},{"status":403,"code":"employee_inactive","when":"El empleado está INACTIVE."},{"status":403,"code":"clocking_blocked_for_employee","when":"El empleado está exento de fichar."},{"status":404,"code":"not_found","when":"No hay ningún empleado con ese employeeId, email o DNI en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Identificar al empleado por `dni` sin el scope employees:read_pii."},{"status":409,"code":"idempotency_key_reused","when":"Ese Idempotency-Key ya se usó para otro fichaje: genera uno nuevo por intento."},{"status":422,"code":"timestamp_out_of_window","when":"deviceTimestamp difiere más de 5 min de la hora del servidor. El pasado va por correcciones."}]}},"/v1/clock/break/end":{"post":{"tags":["Fichajes"],"summary":"Terminar pausa","description":"Registra el fin de pausa y la vuelta al trabajo en el mismo instante (dos fichajes, de forma atómica). 409 si no hay pausa abierta.\n\n**Scope:** `clock:write`","operationId":"postClockBreakEnd","x-scope":"clock:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Clave única por intento lógico (≤ 128 caracteres). Un reintento con la misma clave devuelve el mismo fichaje, nunca uno duplicado.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"locationId":{"description":"Centro de trabajo. Si se omite en una salida, hereda el de la entrada.","type":"string","minLength":1,"maxLength":64},"deviceTimestamp":{"description":"Hora del dispositivo, como evidencia. La hora del fichaje es la del servidor; más de ±5 min de diferencia → 422.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},"additionalProperties":false},"example":{"email":"ana.garcia@example.com"}}}},"responses":{"201":{"description":"Pausa terminada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockAction"},"example":{"object":"clockAction","action":"BREAK_END","state":"working","entry":{"object":"clockEntry","id":918282,"employeeId":4821,"type":"BREAK_END","timestamp":"2026-09-15T11:30:15.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T11:30:15.000Z","updatedAt":"2026-09-15T11:30:15.000Z","deletedAt":null},"entries":[{"object":"clockEntry","id":918282,"employeeId":4821,"type":"BREAK_END","timestamp":"2026-09-15T11:30:15.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T11:30:15.000Z","updatedAt":"2026-09-15T11:30:15.000Z","deletedAt":null},{"object":"clockEntry","id":918283,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T11:30:15.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":null,"minutesLate":null,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T11:30:15.000Z","updatedAt":"2026-09-15T11:30:15.000Z","deletedAt":null}],"idempotentReplay":false}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"clock_state_conflict","when":"`state: NO_ACTIVE_BREAK`: no hay ninguna pausa abierta."},{"status":403,"code":"api_clocking_disabled","when":"La empresa no ha activado el fichaje por API (Ajustes → API)."},{"status":403,"code":"employee_inactive","when":"El empleado está INACTIVE."},{"status":403,"code":"clocking_blocked_for_employee","when":"El empleado está exento de fichar."},{"status":404,"code":"not_found","when":"No hay ningún empleado con ese employeeId, email o DNI en tu empresa."},{"status":403,"code":"insufficient_scope","when":"Identificar al empleado por `dni` sin el scope employees:read_pii."},{"status":409,"code":"idempotency_key_reused","when":"Ese Idempotency-Key ya se usó para otro fichaje: genera uno nuevo por intento."},{"status":422,"code":"timestamp_out_of_window","when":"deviceTimestamp difiere más de 5 min de la hora del servidor. El pasado va por correcciones."}]}},"/v1/clock-corrections":{"get":{"tags":["Correcciones"],"summary":"Solicitudes de corrección","description":"Ordenadas de la más reciente a la más antigua. `from`/`to` filtran por fecha de creación.\n\n**Scope:** `corrections:read`","operationId":"getClockCorrections","x-scope":"corrections:read","parameters":[{"name":"status","in":"query","required":false,"description":"PENDING para la bandeja de aprobaciones.","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED"]},"example":"PENDING"},{"name":"employeeId","in":"query","required":false,"description":"Solo las de este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"name":"requestType","in":"query","required":false,"description":"Solo este tipo de solicitud.","schema":{"type":"string","enum":["MISSING_CLOCK_IN","MISSING_CLOCK_OUT","INCORRECT_TIME","MANUAL_FULL_SHIFT","MANUAL_BREAK"]}},{"name":"from","in":"query","required":false,"description":"Creadas desde este día (inclusive).","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Creadas hasta este día (inclusive). Máximo 366 días.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Resultados por página (máx. 500).","schema":{"default":50,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClockCorrection"}}}}]},"example":{"object":"list","data":[{"object":"clockCorrection","id":"cm1corr8k2p0007qx3n5v1b9d","employeeId":4821,"clockEntryId":null,"requestType":"MANUAL_FULL_SHIFT","missingType":null,"proposedTime":null,"originalTime":null,"manual":{"shiftDate":"2026-09-14","start":"2026-09-14T07:00:00.000Z","end":"2026-09-14T15:00:00.000Z"},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"reason":"Olvidé fichar: estuve todo el día en la obra de Valdespartera.","status":"PENDING","reviewedAt":null,"reviewedById":null,"rejectionReason":null,"isAutoApproved":false,"createdAt":"2026-09-15T07:05:12.000Z","updatedAt":"2026-09-15T07:05:12.000Z"}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":400,"code":"date_range_too_large","when":"Más de 366 días entre from y to."}]},"post":{"tags":["Correcciones"],"summary":"Solicitar una corrección","description":"La única vía para cambiar el pasado del registro horario. Nace PENDIENTE y la aprueba una persona desde el panel (o por API con corrections:manage). Dos formas:\n\n`type: \"SINGLE\"` corrige o añade UN extremo (entrada o salida). Corregir entrada y salida de una misma sesión son dos solicitudes independientes: si la sesión se desplaza a más tarde, envía primero la salida.\n\n`type: \"FULL_SHIFT\"` registra una jornada completa olvidada en una sola solicitud (recomendado). Con `autoApprove: true` y corrections:manage, los fichajes se crean en el acto y figura como autor el administrador que creó la clave. Las jornadas de un empleado ADMINISTRADOR solo se admiten así.\n\n**Scope:** `corrections:write`","operationId":"postClockCorrections","x-scope":"corrections:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"type":{"description":"Corregir o añadir UN extremo (entrada o salida).","type":"string","const":"SINGLE"},"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"missingType":{"description":"Qué extremo se corrige o falta.","type":"string","enum":["IN","OUT"]},"proposedTime":{"description":"Instante propuesto (ISO-8601 con zona).","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"},"clockEntryId":{"description":"Fichaje a corregir. Sin él, se propone uno que falta.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"pairEntryId":{"description":"El otro extremo de la misma sesión, si lo conoces.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"locationId":{"description":"Centro del fichaje.","type":"string","minLength":1,"maxLength":64},"reason":{"description":"Motivo (mínimo 10 caracteres): lo lee quien la aprueba.","type":"string","minLength":10,"maxLength":1000},"autoApprove":{"description":"Aprobar en la misma llamada (requiere corrections:manage).","default":false,"type":"boolean"}},"required":["type","missingType","proposedTime","reason"],"additionalProperties":false},{"type":"object","properties":{"type":{"description":"Jornada completa olvidada: entrada y salida en una sola solicitud.","type":"string","const":"FULL_SHIFT"},"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"shiftDate":{"description":"Día de la jornada (YYYY-MM-DD).","type":"string"},"clockInTime":{"description":"Hora de entrada (HH:mm, hora local de la empresa).","type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"clockOutTime":{"description":"Hora de salida (HH:mm). Si es anterior a la entrada, sale al día siguiente (turno de noche).","type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"locationId":{"description":"Centro de la jornada.","type":"string","minLength":1,"maxLength":64},"reason":{"description":"Motivo (mínimo 10 caracteres): lo lee quien la aprueba.","type":"string","minLength":10,"maxLength":1000},"autoApprove":{"description":"Crear los fichajes en el acto (requiere corrections:manage).","default":false,"type":"boolean"}},"required":["type","shiftDate","clockInTime","clockOutTime","reason"],"additionalProperties":false}]},"example":{"type":"FULL_SHIFT","employeeId":4821,"shiftDate":"2026-09-14","clockInTime":"09:00","clockOutTime":"17:00","reason":"Olvidé fichar: estuve todo el día en la obra de Valdespartera."}}}},"responses":{"201":{"description":"Solicitud creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockCorrection"},"example":{"object":"clockCorrection","id":"cm1corr8k2p0007qx3n5v1b9d","employeeId":4821,"clockEntryId":null,"requestType":"MANUAL_FULL_SHIFT","missingType":null,"proposedTime":null,"originalTime":null,"manual":{"shiftDate":"2026-09-14","start":"2026-09-14T07:00:00.000Z","end":"2026-09-14T15:00:00.000Z"},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"reason":"Olvidé fichar: estuve todo el día en la obra de Valdespartera.","status":"PENDING","reviewedAt":null,"reviewedById":null,"rejectionReason":null,"isAutoApproved":false,"createdAt":"2026-09-15T07:05:12.000Z","updatedAt":"2026-09-15T07:05:12.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":422,"code":"validation_failed","when":"Fecha u hora futuras (por API solo se corrige el pasado), o jornada de un ADMIN sin autoApprove."},{"status":403,"code":"insufficient_scope","when":"autoApprove sin el scope corrections:manage, o el empleado por `dni` sin employees:read_pii."},{"status":403,"code":"key_owner_required","when":"autoApprove, pero el administrador que creó la clave ya no lo es."},{"status":404,"code":"not_found","when":"El empleado, el fichaje (`clockEntryId`/`pairEntryId`) o el centro no existen en tu empresa."}]}},"/v1/clock-corrections/{id}":{"get":{"tags":["Correcciones"],"summary":"Una solicitud de corrección","description":"Una solicitud por su id, con su estado actual.\n\n**Scope:** `corrections:read`","operationId":"getClockCorrectionsId","x-scope":"corrections:read","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la solicitud de corrección.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1corr8k2p0007qx3n5v1b9d"}],"responses":{"200":{"description":"La solicitud","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockCorrection"},"example":{"object":"clockCorrection","id":"cm1corr8k2p0007qx3n5v1b9d","employeeId":4821,"clockEntryId":null,"requestType":"MANUAL_FULL_SHIFT","missingType":null,"proposedTime":null,"originalTime":null,"manual":{"shiftDate":"2026-09-14","start":"2026-09-14T07:00:00.000Z","end":"2026-09-14T15:00:00.000Z"},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"reason":"Olvidé fichar: estuve todo el día en la obra de Valdespartera.","status":"PENDING","reviewedAt":null,"reviewedById":null,"rejectionReason":null,"isAutoApproved":false,"createdAt":"2026-09-15T07:05:12.000Z","updatedAt":"2026-09-15T07:05:12.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/clock-corrections/{id}/approve":{"post":{"tags":["Correcciones"],"summary":"Aprobar una corrección","description":"Aplica la corrección sobre el registro horario (la cadena de integridad se vuelve a firmar) y avisa al empleado. Figura como revisor el administrador que creó la clave (403 `key_owner_required` si ya no lo es).\n\n**Scope:** `corrections:manage`","operationId":"postClockCorrectionsIdApprove","x-scope":"corrections:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la solicitud de corrección.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1corr8k2p0007qx3n5v1b9d"}],"responses":{"200":{"description":"Solicitud revisada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockCorrection"},"example":{"object":"clockCorrection","id":"cm1corr8k2p0007qx3n5v1b9d","employeeId":4821,"clockEntryId":null,"requestType":"MANUAL_FULL_SHIFT","missingType":null,"proposedTime":null,"originalTime":null,"manual":{"shiftDate":"2026-09-14","start":"2026-09-14T07:00:00.000Z","end":"2026-09-14T15:00:00.000Z"},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"reason":"Olvidé fichar: estuve todo el día en la obra de Valdespartera.","status":"APPROVED","reviewedAt":"2026-09-15T09:40:31.000Z","reviewedById":17,"rejectionReason":null,"isAutoApproved":false,"createdAt":"2026-09-15T07:05:12.000Z","updatedAt":"2026-09-15T09:40:31.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"invalid_state","when":"La solicitud ya no está PENDING (`status` dice cómo quedó)."},{"status":403,"code":"key_owner_required","when":"El administrador que creó la clave ya no lo es: crea una clave nueva."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/clock-corrections/{id}/reject":{"post":{"tags":["Correcciones"],"summary":"Rechazar una corrección","description":"Rechaza la solicitud con un motivo (se envía al empleado). El registro horario no cambia.\n\n**Scope:** `corrections:manage`","operationId":"postClockCorrectionsIdReject","x-scope":"corrections:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la solicitud de corrección.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1corr8k2p0007qx3n5v1b9d"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"Motivo del rechazo (mínimo 10 caracteres): se envía al empleado.","type":"string","minLength":10,"maxLength":1000}},"required":["reason"],"additionalProperties":false},"example":{"reason":"Ese día estabas de vacaciones: revisa la fecha."}}}},"responses":{"200":{"description":"Solicitud rechazada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClockCorrection"},"example":{"object":"clockCorrection","id":"cm1corr8k2p0007qx3n5v1b9d","employeeId":4821,"clockEntryId":null,"requestType":"MANUAL_FULL_SHIFT","missingType":null,"proposedTime":null,"originalTime":null,"manual":{"shiftDate":"2026-09-14","start":"2026-09-14T07:00:00.000Z","end":"2026-09-14T15:00:00.000Z"},"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"reason":"Olvidé fichar: estuve todo el día en la obra de Valdespartera.","status":"REJECTED","reviewedAt":"2026-09-15T09:40:31.000Z","reviewedById":17,"rejectionReason":"Ese día estabas de vacaciones: revisa la fecha.","isAutoApproved":false,"createdAt":"2026-09-15T07:05:12.000Z","updatedAt":"2026-09-15T09:40:31.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"invalid_state","when":"La solicitud ya no está PENDING."},{"status":403,"code":"key_owner_required","when":"El administrador que creó la clave ya no lo es."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/leave-types":{"get":{"tags":["Ausencias"],"summary":"Tipos de ausencia","description":"Catálogo de la empresa (configurable por cada una). Integra por `code`, no por el nombre. Los tipos con `isSystem: true` los gestiona FichMe (p. ej. el descanso compensatorio de la bolsa de horas): aparecen en las ausencias pero no se pueden usar al crearlas.\n\n**Scope:** `absences:read`","operationId":"getLeaveTypes","x-scope":"absences:read","parameters":[{"name":"includeInactive","in":"query","required":false,"description":"Incluir los tipos desactivados.","schema":{"type":"string"}}],"responses":{"200":{"description":"Lista de tipos","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LeaveType"}}}}]},"example":{"object":"list","data":[{"object":"leaveType","id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones","description":"Vacaciones anuales retribuidas.","color":"#3B82F6","unit":"DAYS","dayCountType":"BUSINESS_DAYS","requiresBalance":true,"requiresApproval":true,"requiresDocument":false,"requiresReason":false,"allowHalfDays":true,"isPaid":true,"blockClocking":true,"affectsWorkingDays":true,"isActive":true,"isSystem":false,"createdAt":"2025-01-08T11:20:00.000Z","updatedAt":"2026-01-02T09:00:00.000Z"}],"page":1,"limit":1,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."}]}},"/v1/leave-requests":{"get":{"tags":["Ausencias"],"summary":"Ausencias","description":"Solicitudes de ausencia (vacaciones, permisos, bajas…), con su estado. `from`/`to` devuelven las que se solapan con el periodo. Para el detalle día a día (qué días cuenta y cuántas horas descuenta) usa `GET /v1/work-sessions`, que aplica el mismo calendario que el informe de fichajes. Sin employees:read_pii, las ausencias de salud salen con el tipo `RESTRICTED` y ninguna trae los motivos (texto libre).\n\n**Scope:** `absences:read`","operationId":"getLeaveRequests","x-scope":"absences:read","parameters":[{"name":"from","in":"query","required":false,"description":"Ausencias que se solapan con [from, to]. Máximo 366 días.","schema":{"type":"string"},"example":"2026-10-01"},{"name":"to","in":"query","required":false,"description":"Último día del periodo (inclusive).","schema":{"type":"string"},"example":"2026-10-31"},{"name":"updatedSince","in":"query","required":false,"description":"Sincronización incremental (ver guía).","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-]\\d{2}:\\d{2})))$"}},{"name":"cursor","in":"query","required":false,"description":"Cursor de nextCursor (solo con updatedSince).","schema":{"type":"string","maxLength":200}},{"name":"employeeId","in":"query","required":false,"description":"Solo las de este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"name":"leaveTypeId","in":"query","required":false,"description":"Solo este tipo (por id).","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"leaveTypeCode","in":"query","required":false,"description":"Solo este tipo (por código, p. ej. VACATION).","schema":{"type":"string","minLength":1,"maxLength":50}},{"name":"status","in":"query","required":false,"description":"PENDING para la bandeja de aprobaciones.","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED"]},"example":"APPROVED"},{"name":"source","in":"query","required":false,"description":"Solo las registradas por este origen.","schema":{"type":"string","enum":["EMPLOYEE","ADMIN","API","SYSTEM"]}},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Resultados por página (máx. 500).","schema":{"default":50,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LeaveRequest"}}}}]},"example":{"object":"list","data":[{"object":"leaveRequest","id":"cm1lr5q2w0009qx4m7c3z8k1m","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"unit":"DAYS","startDate":"2026-10-13","endDate":"2026-10-16","startHalf":null,"endHalf":null,"startTime":null,"endTime":null,"hours":null,"businessDays":4,"status":"APPROVED","source":"API","reason":"Puente del Pilar","reviewedAt":"2026-09-16T08:02:40.000Z","reviewedById":17,"rejectionReason":null,"cancelledAt":null,"createdAt":"2026-09-15T16:20:03.000Z","updatedAt":"2026-09-16T08:02:40.000Z"}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":400,"code":"date_range_too_large","when":"Más de 366 días entre from y to."},{"status":400,"code":"conflicting_filters","when":"from/to y updatedSince a la vez: usa uno solo."},{"status":403,"code":"insufficient_scope","when":"Filtrar por un tipo de ausencia de salud (baja, consulta médica…) sin employees:read_pii."}]},"post":{"tags":["Ausencias"],"summary":"Registrar una ausencia","description":"Crea la ausencia PENDIENTE de aprobación, con las mismas validaciones que el panel (solapes → 409 `overlap`, saldo → 422 `leave_balance_insufficient`) y aviso a los administradores. Con `autoApprove: true` y absences:manage se aprueba en la misma llamada; figura como revisor el administrador que creó la clave.\n\n**Scope:** `absences:write`","operationId":"postLeaveRequests","x-scope":"absences:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employeeId":{"description":"Id del empleado en FichMe.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"description":"Email del empleado (alternativa a employeeId).","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"dni":{"description":"DNI/NIE del empleado (alternativa a employeeId). Requiere el scope employees:read_pii.","type":"string","minLength":5,"maxLength":20},"leaveTypeId":{"description":"Tipo de ausencia por id.","type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"leaveTypeCode":{"description":"Tipo de ausencia por código (alternativa a leaveTypeId).","type":"string","minLength":1,"maxLength":50},"startDate":{"description":"Primer día (YYYY-MM-DD).","type":"string"},"endDate":{"description":"Último día (YYYY-MM-DD), inclusive.","type":"string"},"startHalf":{"description":"Medio día al inicio (si el tipo lo admite).","type":"string","enum":["MORNING","AFTERNOON"]},"endHalf":{"description":"Medio día al final (si el tipo lo admite).","type":"string","enum":["MORNING","AFTERNOON"]},"startTime":{"description":"Ausencias por horas: hora de inicio (HH:mm).","type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"endTime":{"description":"Ausencias por horas: hora de fin (HH:mm).","type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"hours":{"description":"Ausencias por horas: alternativa a startTime/endTime.","type":"number","exclusiveMinimum":0,"maximum":24},"reason":{"description":"Motivo (lo ve quien la aprueba).","type":"string","minLength":1,"maxLength":1000},"autoApprove":{"description":"Aprobar en la misma llamada (requiere absences:manage).","default":false,"type":"boolean"}},"required":["startDate","endDate"],"additionalProperties":false},"example":{"employeeId":4821,"leaveTypeCode":"VACATION","startDate":"2026-10-13","endDate":"2026-10-16","reason":"Puente del Pilar"}}}},"responses":{"201":{"description":"Ausencia creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveRequest"},"example":{"object":"leaveRequest","id":"cm1lr5q2w0009qx4m7c3z8k1m","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"unit":"DAYS","startDate":"2026-10-13","endDate":"2026-10-16","startHalf":null,"endHalf":null,"startTime":null,"endTime":null,"hours":null,"businessDays":4,"status":"PENDING","source":"API","reason":"Puente del Pilar","reviewedAt":null,"reviewedById":null,"rejectionReason":null,"cancelledAt":null,"createdAt":"2026-09-15T16:20:03.000Z","updatedAt":"2026-09-15T16:20:03.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."},"503":{"$ref":"#/components/responses/Error","description":"Servicio no disponible temporalmente: reintenta tras Retry-After."}},"x-errors":[{"status":409,"code":"overlap","when":"Se solapa con otra ausencia del empleado."},{"status":422,"code":"leave_balance_insufficient","when":"No le queda cupo suficiente (`details` dice cuánto)."},{"status":422,"code":"validation_failed","when":"El tipo está desactivado o es de sistema, o las fechas no encajan con el tipo."},{"status":404,"code":"not_found","when":"El empleado o el tipo de ausencia no existen."},{"status":403,"code":"insufficient_scope","when":"autoApprove sin el scope absences:manage, o el empleado por `dni` sin employees:read_pii."},{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":503,"code":"service_unavailable","when":"Se están actualizando los cupos de ausencias (unos minutos): reintenta tras Retry-After."}]}},"/v1/leave-requests/{id}":{"get":{"tags":["Ausencias"],"summary":"Una ausencia","description":"Una ausencia por su id, con su estado actual.\n\n**Scope:** `absences:read`","operationId":"getLeaveRequestsId","x-scope":"absences:read","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la ausencia.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1lr5q2w0009qx4m7c3z8k1m"}],"responses":{"200":{"description":"La ausencia","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveRequest"},"example":{"object":"leaveRequest","id":"cm1lr5q2w0009qx4m7c3z8k1m","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"unit":"DAYS","startDate":"2026-10-13","endDate":"2026-10-16","startHalf":null,"endHalf":null,"startTime":null,"endTime":null,"hours":null,"businessDays":4,"status":"APPROVED","source":"API","reason":"Puente del Pilar","reviewedAt":"2026-09-16T08:02:40.000Z","reviewedById":17,"rejectionReason":null,"cancelledAt":null,"createdAt":"2026-09-15T16:20:03.000Z","updatedAt":"2026-09-16T08:02:40.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/leave-requests/{id}/approve":{"post":{"tags":["Ausencias"],"summary":"Aprobar una ausencia","description":"Solo ausencias PENDIENTES. Avisa al empleado. Figura como revisor el administrador que creó la clave.\n\n**Scope:** `absences:manage`","operationId":"postLeaveRequestsIdApprove","x-scope":"absences:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la ausencia.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1lr5q2w0009qx4m7c3z8k1m"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"description":"Nota para el empleado (opcional).","type":"string","minLength":1,"maxLength":1000}},"additionalProperties":false},"example":{"notes":"¡Buen puente!"}}}},"responses":{"200":{"description":"Ausencia aprobada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveRequest"},"example":{"object":"leaveRequest","id":"cm1lr5q2w0009qx4m7c3z8k1m","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"unit":"DAYS","startDate":"2026-10-13","endDate":"2026-10-16","startHalf":null,"endHalf":null,"startTime":null,"endTime":null,"hours":null,"businessDays":4,"status":"APPROVED","source":"API","reason":"Puente del Pilar","reviewedAt":"2026-09-16T08:02:40.000Z","reviewedById":17,"rejectionReason":null,"cancelledAt":null,"createdAt":"2026-09-15T16:20:03.000Z","updatedAt":"2026-09-16T08:02:40.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."},"503":{"$ref":"#/components/responses/Error","description":"Servicio no disponible temporalmente: reintenta tras Retry-After."}},"x-errors":[{"status":409,"code":"invalid_state","when":"La ausencia ya no está PENDING (`status` dice cómo quedó)."},{"status":422,"code":"leave_balance_insufficient","when":"Ya no queda cupo para aprobarla."},{"status":403,"code":"key_owner_required","when":"El administrador que creó la clave ya no lo es."},{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":503,"code":"service_unavailable","when":"Se están actualizando los cupos de ausencias (unos minutos): reintenta tras Retry-After."}]}},"/v1/leave-requests/{id}/reject":{"post":{"tags":["Ausencias"],"summary":"Rechazar una ausencia","description":"Solo ausencias PENDIENTES. El motivo (mínimo 10 caracteres) se envía al empleado; el cupo se libera.\n\n**Scope:** `absences:manage`","operationId":"postLeaveRequestsIdReject","x-scope":"absences:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la ausencia.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1lr5q2w0009qx4m7c3z8k1m"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"Motivo del rechazo (mínimo 10 caracteres): se envía al empleado.","type":"string","minLength":10,"maxLength":1000}},"required":["reason"],"additionalProperties":false},"example":{"reason":"Coincide con el cierre trimestral: elige otras fechas."}}}},"responses":{"200":{"description":"Ausencia rechazada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveRequest"},"example":{"object":"leaveRequest","id":"cm1lr5q2w0009qx4m7c3z8k1m","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"unit":"DAYS","startDate":"2026-10-13","endDate":"2026-10-16","startHalf":null,"endHalf":null,"startTime":null,"endTime":null,"hours":null,"businessDays":4,"status":"REJECTED","source":"API","reason":"Puente del Pilar","reviewedAt":"2026-09-16T08:02:40.000Z","reviewedById":17,"rejectionReason":"Coincide con el cierre trimestral: elige otras fechas.","cancelledAt":null,"createdAt":"2026-09-15T16:20:03.000Z","updatedAt":"2026-09-16T08:02:40.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."},"503":{"$ref":"#/components/responses/Error","description":"Servicio no disponible temporalmente: reintenta tras Retry-After."}},"x-errors":[{"status":409,"code":"invalid_state","when":"La ausencia ya no está PENDING."},{"status":403,"code":"key_owner_required","when":"El administrador que creó la clave ya no lo es."},{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":503,"code":"service_unavailable","when":"Se están actualizando los cupos de ausencias (unos minutos): reintenta tras Retry-After."}]}},"/v1/leave-requests/{id}/cancel":{"post":{"tags":["Ausencias"],"summary":"Cancelar una ausencia","description":"Ausencias pendientes o aprobadas. Los días vuelven a su cupo. Los descansos que vienen de la bolsa de horas se anulan desde la bolsa, no desde aquí.\n\n**Scope:** `absences:write`","operationId":"postLeaveRequestsIdCancel","x-scope":"absences:write","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la ausencia.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1lr5q2w0009qx4m7c3z8k1m"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"Motivo de la cancelación (opcional).","type":"string","minLength":1,"maxLength":1000}},"additionalProperties":false},"example":{"reason":"Cambia las fechas del viaje."}}}},"responses":{"200":{"description":"Ausencia cancelada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveRequest"},"example":{"object":"leaveRequest","id":"cm1lr5q2w0009qx4m7c3z8k1m","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"unit":"DAYS","startDate":"2026-10-13","endDate":"2026-10-16","startHalf":null,"endHalf":null,"startTime":null,"endTime":null,"hours":null,"businessDays":4,"status":"CANCELLED","source":"API","reason":"Puente del Pilar","reviewedAt":"2026-09-16T08:02:40.000Z","reviewedById":17,"rejectionReason":null,"cancelledAt":"2026-09-20T10:11:05.000Z","createdAt":"2026-09-15T16:20:03.000Z","updatedAt":"2026-09-20T10:11:05.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."},"503":{"$ref":"#/components/responses/Error","description":"Servicio no disponible temporalmente: reintenta tras Retry-After."}},"x-errors":[{"status":409,"code":"invalid_state","when":"Solo se cancelan ausencias PENDING o APPROVED."},{"status":403,"code":"key_owner_required","when":"El administrador que creó la clave ya no lo es."},{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":503,"code":"service_unavailable","when":"Se están actualizando los cupos de ausencias (unos minutos): reintenta tras Retry-After."}]}},"/v1/leave-balances":{"get":{"tags":["Ausencias"],"summary":"Saldos de ausencias","description":"Cupo por empleado y tipo para un año: asignado, arrastrado, ajustes, consumido y disponible. Equivale al \"saldo de vacaciones\" de una gestoría, pero para cualquier tipo con cupo. Los cupos de tipos de salud (p. ej. horas de consulta médica) solo salen con employees:read_pii.\n\n**Scope:** `absences:read`\n\n**Endpoint pesado:** como mucho 1 petición simultánea por clave.","operationId":"getLeaveBalances","x-scope":"absences:read","parameters":[{"name":"year","in":"query","required":false,"description":"Año del cupo. Por defecto, el actual.","schema":{"type":"integer","minimum":2000,"maximum":2100},"example":2026},{"name":"employeeId","in":"query","required":false,"description":"Solo este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"name":"leaveTypeCode","in":"query","required":false,"description":"Solo este tipo (p. ej. VACATION).","schema":{"type":"string","minLength":1,"maxLength":50},"example":"VACATION"},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Resultados por página (máx. 500).","schema":{"default":50,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LeaveBalance"}}}}]},"example":{"object":"list","data":[{"object":"leaveBalance","employeeId":4821,"leaveType":{"id":"cm1ltvac0001qx7d2k8f4h6jk","code":"VACATION","name":"Vacaciones"},"year":2026,"unit":"DAYS","allocated":22,"carryOver":2,"adjustment":0,"used":12,"available":12,"carriedFromPreviousYears":0}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"El plan de la empresa no incluye la gestión de ausencias."},{"status":404,"code":"not_found","when":"El empleado de `employeeId` no existe."},{"status":429,"code":"too_many_concurrent_requests","when":"Supera el máximo de 1 petición simultánea por clave en los endpoints pesados."},{"status":403,"code":"insufficient_scope","when":"Filtrar por un tipo de ausencia de salud (baja, consulta médica…) sin employees:read_pii."}]}},"/v1/hours-balance":{"get":{"tags":["Balance"],"summary":"Balance de horas","description":"Horas previstas frente a trabajadas, con el motor del Balance de horas del panel (el mismo que usan `GET /v1/work-sessions` y la bolsa de horas). Por defecto, el total del periodo por empleado; con `groupBy=day`, una fila por empleado y día con `scheduleSource` (de dónde sale la jornada prevista), que es lo que se pregunta cuando no cuadran las horas (los elementos son entonces `HoursBalanceDay`).\n\nLa paginación va por EMPLEADOS.\n\n**Scope:** `balance:read`\n\n**Endpoint pesado:** como mucho 1 petición simultánea por clave.","operationId":"getHoursBalance","x-scope":"balance:read","parameters":[{"name":"from","in":"query","required":true,"description":"Primer día del periodo (inclusive).","schema":{"type":"string"},"example":"2026-09-01"},{"name":"to","in":"query","required":true,"description":"Último día del periodo (inclusive). Máximo 366 días.","schema":{"type":"string"},"example":"2026-09-30"},{"name":"employeeId","in":"query","required":false,"description":"Solo este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"name":"locationId","in":"query","required":false,"description":"Empleados de este centro (principal o de pertenencia).","schema":{"type":"string","minLength":1,"maxLength":64}},{"name":"status","in":"query","required":false,"description":"Estado del empleado. ALL incluye a quien se dio de baja en el periodo.","schema":{"default":"ALL","type":"string","enum":["ACTIVE","INACTIVE","ALL"]}},{"name":"groupBy","in":"query","required":false,"description":"employee = total del periodo por empleado; day = una fila por día.","schema":{"default":"employee","type":"string","enum":["employee","day"]}},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"EMPLEADOS por página (máx. 100).","schema":{"default":50,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Lista paginada por empleados","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HoursBalance"}}}}]},"example":{"object":"list","data":[{"object":"hoursBalance","employeeId":4821,"from":"2026-09-01","to":"2026-09-30","workedMinutes":9540,"workedTime":"159:00","assignedMinutes":9450,"assignedTime":"157:30","balanceMinutes":90,"balanceTime":"01:30","breakMinutes":630,"paidBreakMinutes":0,"autoDeductedMinutes":0,"daysWorked":21,"daysWithOpenSegment":0}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":400,"code":"invalid_date_range","when":"Falta from o to, o from es posterior a to."},{"status":400,"code":"date_range_too_large","when":"Más de 366 días."},{"status":429,"code":"too_many_concurrent_requests","when":"Supera el máximo de 1 petición simultánea por clave en los endpoints pesados."}]}},"/v1/shifts":{"get":{"tags":["Turnos"],"summary":"Catálogo de turnos","description":"Turnos definidos en la empresa, con sus tramos, días de aplicación y pausas.\n\n**Scope:** `schedule:read`","operationId":"getShifts","x-scope":"schedule:read","responses":{"200":{"description":"Lista de turnos","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Shift"}}}}]},"example":{"object":"list","data":[{"object":"shift","id":"cm1shmnn0002qx9p4c6v8b2de","name":"Mañana","type":"WORK","color":"#10B981","isNight":false,"isSplit":false,"segments":[{"start":"09:00","end":"17:00"}],"totalHours":7.5,"applicableDays":[1,2,3,4,5],"tolerance":{"entryMinutes":10,"exitMinutes":10},"breaks":[{"id":"cm1brkcm0003qx9p4c6v8b2df","name":"Comida","startTime":"13:00","durationMinutes":30,"isPaid":false,"autoDeduct":false}],"createdAt":"2025-02-03T09:30:00.000Z","updatedAt":"2026-03-10T12:00:00.000Z"}],"page":1,"limit":1,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}}}},"/v1/shift-assignments":{"get":{"tags":["Turnos"],"summary":"Turno de cada empleado por día","description":"Una fila por empleado y día con turno. Resuelve la misma jerarquía que el calendario: el turno pintado en el calendario manda; si no hay, el turno por rango de fechas y, si tampoco, el fijo, siempre que aplique ese día de la semana. Los días sin fila no tienen turno (rige el horario del centro o de la empresa).\n\n**Scope:** `schedule:read`","operationId":"getShiftAssignments","x-scope":"schedule:read","parameters":[{"name":"from","in":"query","required":true,"description":"Primer día (inclusive).","schema":{"type":"string"},"example":"2026-09-14"},{"name":"to","in":"query","required":true,"description":"Último día (inclusive). Máximo 93 días.","schema":{"type":"string"},"example":"2026-09-20"},{"name":"employeeId","in":"query","required":false,"description":"Solo este empleado.","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"example":4821},{"name":"page","in":"query","required":false,"description":"Página, desde 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Resultados por página (máx. 500).","schema":{"default":50,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ShiftAssignment"}}}}]},"example":{"object":"list","data":[{"object":"shiftAssignment","employeeId":4821,"date":"2026-09-15","origin":"DEFAULT","shift":{"id":"cm1shmnn0002qx9p4c6v8b2de","name":"Mañana"},"isDayOff":false,"startTime":"09:00","endTime":"17:00","hours":7.5,"notes":null}],"page":1,"limit":50,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":400,"code":"invalid_date_range","when":"Falta from o to, o from es posterior a to."},{"status":400,"code":"date_range_too_large","when":"Más de 93 días."}]}},"/v1/holidays":{"get":{"tags":["Turnos"],"summary":"Festivos","description":"Festivos del año: los de la empresa y los de cada centro (o los de la empresa más los de un centro con `locationId`). `workingHours` > 0 indica una jornada reducida en vez de un festivo completo.\n\n**Scope:** `schedule:read`","operationId":"getHolidays","x-scope":"schedule:read","parameters":[{"name":"year","in":"query","required":false,"description":"Año. Por defecto, el actual.","schema":{"type":"integer","minimum":2000,"maximum":2100},"example":2026},{"name":"locationId","in":"query","required":false,"description":"Festivos de la empresa más los de este centro.","schema":{"type":"string","minLength":1,"maxLength":64}}],"responses":{"200":{"description":"Lista de festivos","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Holiday"}}}}]},"example":{"object":"list","data":[{"object":"holiday","id":"cm1hol12o0004qx2b7n5c9d3f","date":"2026-10-12","name":"Fiesta Nacional de España","type":"NATIONAL","scope":"COMPANY","locationId":null,"province":null,"workingHours":0,"recurrent":true}],"page":1,"limit":1,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}}}},"/v1/exports":{"post":{"tags":["Exportaciones"],"summary":"Lanzar una exportación","description":"Genera en segundo plano uno de los informes del panel (hasta 2 años). Responde 202 con el id; consulta `GET /v1/exports/{id}` hasta que `status` sea `completed` y descarga el archivo de `downloadUrl`. Si ya hay una exportación idéntica en curso, devuelve esa. Requiere exports:write y employees:read_pii (los informes llevan el DNI).\n\n**Scope:** `exports:write`\n\n**Endpoint pesado:** como mucho 1 petición simultánea por clave.","operationId":"postExports","x-scope":"exports:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dataset":{"description":"clocking = registro de jornada (fichajes); balance = balance de horas; absence = ausencias; hour-bank = bolsa de horas; location-hours = horas por centro.","type":"string","enum":["clocking","balance","absence","hour-bank","location-hours"]},"format":{"description":"pdf = el informe firmado del panel.","default":"xlsx","type":"string","enum":["csv","xlsx","pdf"]},"from":{"description":"Primer día del periodo (YYYY-MM-DD).","type":"string"},"to":{"description":"Último día del periodo (YYYY-MM-DD). Máximo 2 años.","type":"string"},"employeeIds":{"description":"Solo estos empleados (por defecto, todos).","minItems":1,"maxItems":500,"type":"array","items":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"locationId":{"description":"Solo este centro.","type":"string","minLength":1,"maxLength":64},"locationScope":{"description":"Solo clocking: assigned = empleados del centro; clocked = solo los tramos fichados en él.","type":"string","enum":["assigned","clocked"]},"employeeStatus":{"description":"Empleados activos, dados de baja o todos.","default":"all","type":"string","enum":["all","active","inactive"]},"includeModifications":{"description":"Solo clocking: anexo con el detalle de modificaciones.","default":true,"type":"boolean"}},"required":["dataset","from","to"],"additionalProperties":false},"example":{"dataset":"clocking","format":"pdf","from":"2026-09-01","to":"2026-09-30"}}}},"responses":{"202":{"description":"Exportación en cola","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"},"example":{"object":"export","id":"cm1exp7t0005qx6c3m9b2v8zq","status":"pending","dataset":"clocking","format":"pdf","from":"2026-09-01","to":"2026-09-30","progress":0,"rows":null,"sizeBytes":null,"downloadUrl":null,"error":null,"createdAt":"2026-10-01T07:00:03.000Z","completedAt":null,"expiresAt":"2026-10-02T07:00:03.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"insufficient_scope","when":"Falta employees:read_pii: los informes llevan el DNI de cada empleado."},{"status":400,"code":"date_range_too_large","when":"Más de 2 años."},{"status":403,"code":"plan_upgrade_required","when":"dataset hour-bank sin la bolsa de horas en el plan."},{"status":422,"code":"validation_failed","when":"dataset hour-bank con la bolsa de horas desactivada en la empresa."},{"status":404,"code":"not_found","when":"Algún empleado de employeeIds o el centro no existen."}]}},"/v1/exports/{id}":{"get":{"tags":["Exportaciones"],"summary":"Estado y descarga de una exportación","description":"Consulta cada pocos segundos (con backoff) hasta `completed` o `failed`. `downloadUrl` caduca en una hora: vuelve a pedir este endpoint para obtener otra. El archivo se borra 24 h después de crearse.\n\n**Scope:** `exports:read`","operationId":"getExportsId","x-scope":"exports:read","parameters":[{"name":"id","in":"path","required":true,"description":"Id de la exportación.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1exp7t0005qx6c3m9b2v8zq"}],"responses":{"200":{"description":"La exportación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"},"example":{"object":"export","id":"cm1exp7t0005qx6c3m9b2v8zq","status":"completed","dataset":"clocking","format":"pdf","from":"2026-09-01","to":"2026-09-30","progress":100,"rows":412,"sizeBytes":183422,"downloadUrl":"https://api.fichme.com/api/files/eyJqb2IiOiJjbTFleHA3dDAwMDUifQ/registro-jornada-2026-09.pdf","error":null,"createdAt":"2026-10-01T07:00:03.000Z","completedAt":"2026-10-01T07:00:41.000Z","expiresAt":"2026-10-02T07:00:03.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"insufficient_scope","when":"Falta employees:read_pii: los informes llevan el DNI de cada empleado."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"Webhooks de la empresa","description":"Endpoints que reciben los eventos. Cada evento llega como POST JSON `{ id, object: \"event\", type, apiVersion, createdAt, companyId, data: { object } }` con las cabeceras `FichMe-Event`, `FichMe-Event-Id`, `FichMe-Delivery-Id` y `FichMe-Signature: t=<unix>,v1=<hex>`, donde v1 = HMAC-SHA256(secreto, \"<t>.<cuerpo>\"). Responde 2xx en menos de 10 s; si no, se reintenta a 1 min, 5 min, 30 min, 2 h y 12 h. Entrega «al menos una vez» y sin orden garantizado: deduplica por `id` del evento. Tipos: `clockEntry.created`, `clockEntry.updated`, `clockCorrection.created`, `clockCorrection.approved`, `clockCorrection.rejected`, `leaveRequest.created`, `leaveRequest.approved`, `leaveRequest.rejected`, `leaveRequest.cancelled`, `employee.created`, `employee.updated`, `employee.deactivated`, `employee.deleted`.\n\n**Scope:** `webhooks:manage`","operationId":"getWebhooks","x-scope":"webhooks:manage","responses":{"200":{"description":"Lista de webhooks","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}}}]},"example":{"object":"list","data":[{"object":"webhookEndpoint","id":"cm1whk4r0006qx8v2n6c3b7xy","url":"https://erp.example.com/webhooks/fichme","description":"ERP de nóminas","events":["clockEntry.created","leaveRequest.approved"],"status":"ACTIVE","failingSince":null,"disabledReason":null,"secretLast4":"hJ2l","createdAt":"2026-09-10T09:00:00.000Z","updatedAt":"2026-09-10T09:00:00.000Z","lastDelivery":{"status":"DELIVERED","httpStatus":200,"at":"2026-09-15T06:58:33.000Z"}}],"page":1,"limit":1,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"Los webhooks están en los planes Business y Enterprise."}]},"post":{"tags":["Webhooks"],"summary":"Crear un webhook","description":"Devuelve el secreto de firma UNA sola vez. Como mucho 10 webhooks por empresa.\n\n**Scope:** `webhooks:manage`","operationId":"postWebhooks","x-scope":"webhooks:manage","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"description":"https://… pública (no se admiten IPs ni redes internas).","type":"string","minLength":8,"maxLength":2048},"description":{"description":"Descripción libre (≤ 200 caracteres).","type":"string","maxLength":200},"events":{"description":"Eventos a los que se suscribe, o [\"*\"] para todos.","minItems":1,"maxItems":20,"type":"array","items":{"type":"string","enum":["*","clockEntry.created","clockEntry.updated","clockCorrection.created","clockCorrection.approved","clockCorrection.rejected","leaveRequest.created","leaveRequest.approved","leaveRequest.rejected","leaveRequest.cancelled","employee.created","employee.updated","employee.deactivated","employee.deleted"]}}},"required":["url","events"],"additionalProperties":false},"example":{"url":"https://erp.example.com/webhooks/fichme","description":"ERP de nóminas","events":["clockEntry.created","leaveRequest.approved"]}}}},"responses":{"201":{"description":"Webhook creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecret"},"example":{"endpoint":{"object":"webhookEndpoint","id":"cm1whk4r0006qx8v2n6c3b7xy","url":"https://erp.example.com/webhooks/fichme","description":"ERP de nóminas","events":["clockEntry.created","leaveRequest.approved"],"status":"ACTIVE","failingSince":null,"disabledReason":null,"secretLast4":"hJ2l","createdAt":"2026-09-10T09:00:00.000Z","updatedAt":"2026-09-10T09:00:00.000Z","lastDelivery":null},"secret":"whsec_q9Xv2LmT7pR4sW8zN1bK6cY3fH0dJ5gA2eU7iO4hJ2l"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."},"503":{"$ref":"#/components/responses/Error","description":"Servicio no disponible temporalmente: reintenta tras Retry-After."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"Los webhooks están en los planes Business y Enterprise."},{"status":422,"code":"validation_failed","when":"URL no https, con IP o de una red interna; evento desconocido; o ya hay 10 webhooks."},{"status":503,"code":"service_unavailable","when":"Los webhooks no están disponibles en este momento."}]}},"/v1/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"Un webhook","description":"Un webhook con el resultado de su última entrega.\n\n**Scope:** `webhooks:manage`","operationId":"getWebhooksId","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"}],"responses":{"200":{"description":"El webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"},"example":{"object":"webhookEndpoint","id":"cm1whk4r0006qx8v2n6c3b7xy","url":"https://erp.example.com/webhooks/fichme","description":"ERP de nóminas","events":["clockEntry.created","leaveRequest.approved"],"status":"ACTIVE","failingSince":null,"disabledReason":null,"secretLast4":"hJ2l","createdAt":"2026-09-10T09:00:00.000Z","updatedAt":"2026-09-10T09:00:00.000Z","lastDelivery":{"status":"DELIVERED","httpStatus":200,"at":"2026-09-15T06:58:33.000Z"}}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]},"patch":{"tags":["Webhooks"],"summary":"Editar, pausar o reactivar un webhook","description":"Cambia solo los campos enviados. Reactivar uno DISABLED le da otra oportunidad completa.\n\n**Scope:** `webhooks:manage`","operationId":"patchWebhooksId","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"description":"Nueva URL https.","type":"string","minLength":8,"maxLength":2048},"description":{"description":"Descripción (null la borra).","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"events":{"description":"Conjunto COMPLETO de eventos suscritos.","minItems":1,"maxItems":20,"type":"array","items":{"type":"string","enum":["*","clockEntry.created","clockEntry.updated","clockCorrection.created","clockCorrection.approved","clockCorrection.rejected","leaveRequest.created","leaveRequest.approved","leaveRequest.rejected","leaveRequest.cancelled","employee.created","employee.updated","employee.deactivated","employee.deleted"]}},"status":{"description":"PAUSED deja de enviar; ACTIVE lo reanuda (y reactiva uno DISABLED).","type":"string","enum":["ACTIVE","PAUSED"]}},"additionalProperties":false},"example":{"status":"PAUSED"}}}},"responses":{"200":{"description":"Webhook actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"},"example":{"object":"webhookEndpoint","id":"cm1whk4r0006qx8v2n6c3b7xy","url":"https://erp.example.com/webhooks/fichme","description":"ERP de nóminas","events":["clockEntry.created","leaveRequest.approved"],"status":"PAUSED","failingSince":null,"disabledReason":null,"secretLast4":"hJ2l","createdAt":"2026-09-10T09:00:00.000Z","updatedAt":"2026-09-16T12:30:00.000Z","lastDelivery":{"status":"DELIVERED","httpStatus":200,"at":"2026-09-15T06:58:33.000Z"}}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":422,"code":"validation_failed","when":"URL no válida, evento desconocido, o no hay nada que cambiar."},{"status":403,"code":"plan_upgrade_required","when":"Reactivar (status ACTIVE) sin webhooks en el plan."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]},"delete":{"tags":["Webhooks"],"summary":"Borrar un webhook","description":"Borra también su historial de entregas.\n\n**Scope:** `webhooks:manage`","operationId":"deleteWebhooksId","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"}],"responses":{"204":{"description":"Borrado (sin cuerpo)"},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/webhooks/{id}/ping":{"post":{"tags":["Webhooks"],"summary":"Enviar un evento de prueba","description":"Encola un evento `webhook.ping` (un solo intento). Consulta el resultado en las entregas.\n\n**Scope:** `webhooks:manage`","operationId":"postWebhooksIdPing","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"}],"responses":{"202":{"description":"Prueba en cola","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPing"},"example":{"deliveryId":"48214"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":409,"code":"invalid_state","when":"El webhook no está ACTIVE: reactívalo antes."},{"status":403,"code":"plan_upgrade_required","when":"Los webhooks están en los planes Business y Enterprise."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/webhooks/{id}/rotate-secret":{"post":{"tags":["Webhooks"],"summary":"Rotar el secreto de firma","description":"El secreto anterior deja de valer al instante; el nuevo se devuelve una sola vez.\n\n**Scope:** `webhooks:manage`","operationId":"postWebhooksIdRotateSecret","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"}],"responses":{"200":{"description":"Secreto nuevo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecret"},"example":{"endpoint":{"object":"webhookEndpoint","id":"cm1whk4r0006qx8v2n6c3b7xy","url":"https://erp.example.com/webhooks/fichme","description":"ERP de nóminas","events":["clockEntry.created","leaveRequest.approved"],"status":"ACTIVE","failingSince":null,"disabledReason":null,"secretLast4":"hJ2l","createdAt":"2026-09-10T09:00:00.000Z","updatedAt":"2026-09-10T09:00:00.000Z","lastDelivery":{"status":"DELIVERED","httpStatus":200,"at":"2026-09-15T06:58:33.000Z"}},"secret":"whsec_q9Xv2LmT7pR4sW8zN1bK6cY3fH0dJ5gA2eU7iO4hJ2l"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":403,"code":"plan_upgrade_required","when":"Los webhooks están en los planes Business y Enterprise."},{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/webhooks/{id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"Historial de entregas","description":"Las más recientes primero. Se conservan 30 días.\n\n**Scope:** `webhooks:manage`","operationId":"getWebhooksIdDeliveries","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"},{"name":"status","in":"query","required":false,"description":"Filtrar por resultado.","schema":{"default":"all","type":"string","enum":["all","failed","pending","delivered"]},"example":"failed"},{"name":"limit","in":"query","required":false,"description":"Cuántas entregas (máx. 200).","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Entregas","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}]},"example":{"object":"list","data":[{"object":"webhookDelivery","id":"48213","eventId":"evt_01K5Q8Z3M2X7C9V4B6N1P8R0TQ","eventType":"clockEntry.created","status":"DELIVERED","attempts":1,"lastStatus":200,"lastError":null,"createdAt":"2026-09-15T06:58:32.000Z","deliveredAt":"2026-09-15T06:58:33.000Z","nextAttemptAt":null}],"page":1,"limit":1,"total":1,"totalPages":1}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}},"/v1/webhooks/{id}/deliveries/{deliveryId}/retry":{"post":{"tags":["Webhooks"],"summary":"Reintentar una entrega","description":"Vuelve a encolar una entrega (con un intento más aunque se hubieran agotado), p. ej. tras arreglar tu servidor.\n\n**Scope:** `webhooks:manage`","operationId":"postWebhooksIdDeliveriesDeliveryIdRetry","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"description":"Id del webhook.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"example":"cm1whk4r0006qx8v2n6c3b7xy"},{"name":"deliveryId","in":"path","required":true,"description":"Id de la entrega.","schema":{"type":"string","pattern":"^\\d{1,19}$"},"example":"48213"}],"responses":{"200":{"description":"Entrega reencolada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"},"example":{"object":"webhookDelivery","id":"48213","eventId":"evt_01K5Q8Z3M2X7C9V4B6N1P8R0TQ","eventType":"clockEntry.created","status":"PENDING","attempts":6,"lastStatus":503,"lastError":"HTTP 503","createdAt":"2026-09-15T06:58:32.000Z","deliveredAt":null,"nextAttemptAt":"2026-09-16T12:31:00.000Z"}}}},"400":{"$ref":"#/components/responses/Error","description":"Petición no válida (`invalid_request`, `invalid_date_range`, `date_range_too_large`, `conflicting_filters`, `page_out_of_range`, `tenant_override_forbidden`)."},"401":{"$ref":"#/components/responses/Error","description":"Clave ausente, no válida, revocada o caducada."},"403":{"$ref":"#/components/responses/Error","description":"Sin el scope necesario, IP no permitida, plan sin API o suscripción inactiva."},"404":{"$ref":"#/components/responses/Error","description":"No existe (o no es de tu empresa: la respuesta es idéntica)."},"409":{"$ref":"#/components/responses/Error","description":"Conflicto con el estado actual."},"422":{"$ref":"#/components/responses/Error","description":"Regla de negocio incumplida."},"429":{"$ref":"#/components/responses/Error","description":"Límite de peticiones, de concurrencia o cuota diaria."}},"x-errors":[{"status":404,"code":"not_found","when":"No existe o no es de tu empresa."}]}}},"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"Clave de API: fm_live_…"},"BearerAuth":{"type":"http","scheme":"bearer","description":"La misma clave como Bearer (Zapier, Make, Postman)."}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"ListEnvelope":{"type":"object","required":["object","data","page","limit","total","totalPages"],"properties":{"object":{"const":"list","description":"Siempre \"list\"."},"data":{"type":"array","items":{},"description":"Los resultados de esta página.","examples":[[]]},"page":{"type":["integer","null"],"description":"Página actual, desde 1 (null con updatedSince).","examples":[1]},"limit":{"type":"integer","description":"Resultados por página pedidos.","examples":[50]},"total":{"type":["integer","null"],"description":"Resultados en total (null con updatedSince).","examples":[1]},"totalPages":{"type":["integer","null"],"description":"Páginas en total (null con updatedSince).","examples":[1]},"nextCursor":{"type":["string","null"],"description":"Solo con updatedSince: cursor de la página siguiente (null si no hay más).","examples":[null]},"hasMore":{"type":"boolean","description":"Solo con updatedSince: quedan más resultados.","examples":[false]}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","description":"Detalle del error.","required":["code","message","param","requestId"],"properties":{"code":{"type":"string","description":"Código estable del catálogo de errores: programa contra él.","examples":["insufficient_scope"]},"message":{"type":"string","description":"Explicación en castellano. Puede cambiar: no la compares.","examples":["Esta operación requiere el scope clock:write."]},"param":{"type":["string","null"],"description":"Campo que provocó el error, si aplica.","examples":[null]},"requestId":{"type":"string","description":"Identificador de la petición (cabecera X-Request-Id): cítalo a soporte.","examples":["req_01K5Q9A1B2C3D4E5F6G7H8J9KM"]}},"additionalProperties":true}}},"Me":{"type":"object","properties":{"object":{"type":"string","const":"me"},"apiKey":{"description":"La clave con la que se hace la llamada.","type":"object","properties":{"id":{"description":"Id interno de la clave.","examples":["cm1key9p0008qx5b3c7n2m4wl"],"type":"string"},"name":{"description":"Nombre que le puso el administrador al crearla.","examples":["Gestoría Pérez"],"type":"string"},"prefix":{"description":"fm_live_<keyId>: identifica la clave sin revelar el secreto (es lo que se ve en el panel).","examples":["fm_live_k7m2p5x4q3ab"],"type":"string"},"scopes":{"description":"Permisos concedidos a la clave.","examples":[["company:read","employees:read","clock:read"]],"type":"array","items":{"type":"string"}},"expiresAt":{"description":"Caducidad de la clave (null = sin caducidad, solo en Enterprise).","examples":["2027-09-15T10:00:00.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","prefix","scopes","expiresAt"],"additionalProperties":false},"company":{"description":"La empresa de la clave: la única cuyos datos ve.","type":"object","properties":{"id":{"description":"Id de la empresa en FichMe.","examples":[1042],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"description":"Nombre comercial.","examples":["Construcciones Ebro"],"type":"string"},"slug":{"description":"Identificador corto (el subdominio del panel).","examples":["construcciones-ebro"],"type":"string"},"timezone":{"description":"Zona horaria IANA: la de las fechas de jornada (`shiftDate`).","examples":["Europe/Madrid"],"type":"string"}},"required":["id","name","slug","timezone"],"additionalProperties":false},"plan":{"description":"Plan de la empresa.","type":"object","properties":{"name":{"description":"Plan contratado.","examples":["Business"],"anyOf":[{"type":"string"},{"type":"null"}]},"webhooks":{"description":"El plan incluye webhooks (Business y Enterprise).","examples":[true],"type":"boolean"}},"required":["name","webhooks"],"additionalProperties":false},"rateLimit":{"description":"Límites que se aplican a esta clave.","type":"object","properties":{"perMinute":{"description":"Peticiones por minuto de esta clave.","examples":[120],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"perDay":{"description":"Cuota diaria de la clave según el plan (se renueva a las 00:00 UTC).","examples":[50000],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxConcurrentHeavy":{"description":"Peticiones pesadas simultáneas (jornadas, balance, saldos, exportaciones).","examples":[1],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["perMinute","perDay","maxConcurrentHeavy"],"additionalProperties":false},"apiVersion":{"description":"Versión de la API.","type":"string","const":"v1"},"serverTime":{"description":"Hora del servidor en UTC: sirve para comprobar el reloj de tu sistema.","examples":["2026-09-15T10:04:12.000Z"],"type":"string"}},"required":["object","apiKey","company","plan","rateLimit","apiVersion","serverTime"],"additionalProperties":false},"Company":{"type":"object","properties":{"object":{"type":"string","const":"company"},"id":{"description":"Id de la empresa en FichMe.","examples":[1042],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"description":"Nombre comercial.","examples":["Construcciones Ebro"],"type":"string"},"legalName":{"description":"Razón social.","examples":["Construcciones Ebro, S.L."],"anyOf":[{"type":"string"},{"type":"null"}]},"taxId":{"description":"CIF de la empresa.","examples":["B50123456"],"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"description":"Identificador corto (el subdominio del panel).","examples":["construcciones-ebro"],"type":"string"},"address":{"description":"Dirección fiscal.","examples":["Calle del Coso 42"],"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"description":"Localidad.","examples":["Zaragoza"],"anyOf":[{"type":"string"},{"type":"null"}]},"province":{"description":"Provincia.","examples":["Zaragoza"],"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"description":"Código postal.","examples":["50004"],"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"description":"País.","examples":["España"],"anyOf":[{"type":"string"},{"type":"null"}]},"timezone":{"description":"Zona horaria IANA contra la que se resuelve `shiftDate`.","examples":["Europe/Madrid"],"type":"string"},"settings":{"description":"Ajustes que hacen falta para interpretar el resto de datos.","type":"object","properties":{"workingDays":{"description":"Días laborables por defecto: 0 = domingo … 6 = sábado.","examples":[[1,2,3,4,5]],"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"lateArrivalThreshold":{"description":"Minutos de tolerancia antes de marcar un retraso.","examples":[10],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"earlyDepartureThreshold":{"description":"Minutos de tolerancia antes de marcar una salida anticipada.","examples":[10],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"mandatoryBreakMinutes":{"description":"Pausa mínima obligatoria de la jornada, en minutos.","examples":[30],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxShiftHours":{"description":"Horas tras las que una jornada abierta se marca incompleta.","examples":[16],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"apiClockingEnabled":{"description":"La empresa permite registrar fichajes por API (lo activa un administrador).","examples":[true],"type":"boolean"},"hourBankEnabled":{"description":"La empresa usa la bolsa de horas.","examples":[true],"type":"boolean"},"geolocationEnabled":{"description":"La empresa pide la ubicación al fichar desde la app.","examples":[false],"type":"boolean"}},"required":["workingDays","lateArrivalThreshold","earlyDepartureThreshold","mandatoryBreakMinutes","maxShiftHours","apiClockingEnabled","hourBankEnabled","geolocationEnabled"],"additionalProperties":false}},"required":["object","id","name","legalName","taxId","slug","address","city","province","postalCode","country","timezone","settings"],"additionalProperties":false},"Location":{"type":"object","properties":{"object":{"type":"string","const":"location"},"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"},"code":{"description":"Código interno del centro, si la empresa lo usa.","examples":["ZGZ"],"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"description":"Dirección.","examples":["Calle del Coso 42"],"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"description":"Localidad.","examples":["Zaragoza"],"anyOf":[{"type":"string"},{"type":"null"}]},"province":{"description":"Provincia (decide los festivos autonómicos).","examples":["Zaragoza"],"anyOf":[{"type":"string"},{"type":"null"}]},"timezone":{"description":"Zona horaria propia del centro (null = la de la empresa).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"description":"El centro está en uso.","examples":[true],"type":"boolean"},"isPrimary":{"description":"Es el centro principal de la empresa.","examples":[true],"type":"boolean"},"isSystem":{"description":"Centro que crea FichMe al dar de alta la empresa («Principal» o «Teletrabajo»). Se puede fichar en él, pero no se asigna a empleados.","examples":[false],"type":"boolean"},"geofence":{"description":"Geovalla: coordenadas del CENTRO, nunca de personas.","type":"object","properties":{"enabled":{"description":"Solo se puede fichar dentro del radio.","examples":[true],"type":"boolean"},"radiusMeters":{"description":"Radio en metros.","examples":[150],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"latitude":{"description":"Latitud del centro.","examples":[41.6523],"anyOf":[{"type":"number"},{"type":"null"}]},"longitude":{"description":"Longitud del centro.","examples":[-0.8773],"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["enabled","radiusMeters","latitude","longitude"],"additionalProperties":false},"createdAt":{"description":"Alta del centro (UTC).","examples":["2025-02-03T09:12:44.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC).","examples":["2026-06-11T15:30:02.000Z"],"type":"string"}},"required":["object","id","name","code","address","city","province","timezone","isActive","isPrimary","isSystem","geofence","createdAt","updatedAt"],"additionalProperties":false},"Employee":{"type":"object","properties":{"object":{"type":"string","const":"employee"},"id":{"description":"Id del empleado en FichMe.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"firstName":{"description":"Nombre.","examples":["Ana"],"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"description":"Apellidos.","examples":["García López"],"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"description":"Nombre completo, como aparece en los informes.","examples":["Ana García López"],"type":"string"},"email":{"description":"Email (también es su usuario de acceso).","examples":["ana.garcia@example.com"],"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"description":"Rol en FichMe. Las cuentas ADMIN solo se modifican desde el panel.","examples":["EMPLOYEE"],"type":"string","enum":["ADMIN","EMPLOYEE"]},"status":{"description":"INACTIVE = dado de baja operativa: no ficha ni ocupa plaza del plan.","examples":["ACTIVE"],"type":"string","enum":["ACTIVE","INACTIVE"]},"activationStatus":{"description":"Estado del acceso a FichMe: PENDING_SETUP | PENDING_ACTIVATION | EMAIL_FAILED | ACTIVATED | NOT_APPLICABLE.","examples":["ACTIVATED"],"type":"string"},"jobTitle":{"description":"Puesto.","examples":["Técnica de obra"],"anyOf":[{"type":"string"},{"type":"null"}]},"department":{"description":"Departamento.","examples":["Producción"],"anyOf":[{"type":"string"},{"type":"null"}]},"hireDate":{"description":"Fecha de alta (YYYY-MM-DD).","examples":["2024-03-01"],"anyOf":[{"description":"YYYY-MM-DD","type":"string"},{"type":"null"}]},"seniorityDate":{"description":"Fecha de antigüedad (YYYY-MM-DD).","examples":["2024-03-01"],"anyOf":[{"description":"YYYY-MM-DD","type":"string"},{"type":"null"}]},"contract":{"description":"Datos del contrato.","type":"object","properties":{"type":{"description":"FULL_TIME | PART_TIME | TEMPORARY.","examples":["FULL_TIME"],"anyOf":[{"type":"string"},{"type":"null"}]},"weeklyHours":{"description":"Horas semanales contratadas.","examples":[40],"anyOf":[{"type":"number"},{"type":"null"}]},"annualHours":{"description":"Horas anuales contratadas.","examples":[1776],"anyOf":[{"type":"number"},{"type":"null"}]},"isNightWorker":{"description":"Trabajador nocturno (art. 36 ET).","examples":[false],"type":"boolean"}},"required":["type","weeklyHours","annualHours","isNightWorker"],"additionalProperties":false},"location":{"description":"Centro principal.","anyOf":[{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"locations":{"description":"Todos los centros a los que pertenece.","type":"array","items":{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"},"isPrimary":{"description":"Es su centro principal.","examples":[true],"type":"boolean"}},"required":["id","name","isPrimary"],"additionalProperties":false}},"clockingPolicy":{"description":"Excepciones del empleado a la política de fichaje de la empresa.","type":"object","properties":{"exempt":{"description":"Exento de fichar (no aparece en los informes de jornada).","examples":[false],"type":"boolean"},"web":{"description":"Puede fichar desde la web (null = lo que diga la empresa).","examples":[null],"anyOf":[{"type":"boolean"},{"type":"null"}]},"app":{"description":"Puede fichar desde la app (null = lo que diga la empresa).","examples":[true],"anyOf":[{"type":"boolean"},{"type":"null"}]},"terminal":{"description":"Puede fichar en un terminal con PIN (null = lo que diga la empresa).","examples":[null],"anyOf":[{"type":"boolean"},{"type":"null"}]},"requireGeolocation":{"description":"Se le exige ubicación al fichar (null = lo que diga la empresa).","examples":[null],"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["exempt","web","app","terminal","requireGeolocation"],"additionalProperties":false},"identity":{"description":"Datos fiscales. Solo con el scope employees:read_pii; sin él, null.","anyOf":[{"type":"object","properties":{"taxId":{"description":"DNI/NIE.","examples":["12345678Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"socialSecurityNumber":{"description":"Nº de afiliación a la Seguridad Social.","examples":["281234567840"],"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"description":"Teléfono.","examples":["+34 600 123 456"],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["taxId","socialSecurityNumber","phone"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"description":"Alta en FichMe (UTC).","examples":["2024-02-20T10:05:13.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC). Es la marca de la sincronización incremental.","examples":["2026-09-01T08:14:55.000Z"],"type":"string"},"deletedAt":{"description":"Baja lógica (UTC), o null si sigue en la empresa.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","firstName","lastName","name","email","role","status","activationStatus","jobTitle","department","hireDate","seniorityDate","contract","location","locations","clockingPolicy","identity","createdAt","updatedAt","deletedAt"],"additionalProperties":false},"ClockEntry":{"type":"object","properties":{"object":{"type":"string","const":"clockEntry"},"id":{"description":"Id del fichaje.","examples":[918273],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"employeeId":{"description":"Empleado que fichó.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"type":{"description":"IN = entrada · OUT = salida · BREAK_START / BREAK_END = inicio y fin de pausa.","examples":["IN"],"type":"string","enum":["IN","OUT","BREAK_START","BREAK_END"]},"timestamp":{"description":"Instante del fichaje en UTC (la hora oficial, la del servidor).","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"shiftDate":{"description":"Día de jornada en la zona horaria de la empresa. Un turno de noche que sale de madrugada conserva el día de la entrada.","examples":["2026-09-15"],"type":"string"},"method":{"description":"Canal por el que se fichó.","examples":["APP"],"type":"string","enum":["WEB","APP","QR","KIOSK","SLACK","WHATSAPP","API"]},"source":{"description":"Origen técnico: WEB | MOBILE | KIOSK | SLACK | WHATSAPP | API.","examples":["MOBILE"],"type":"string"},"status":{"description":"INCOMPLETE = la jornada se quedó sin cerrar y la marcó el sistema.","examples":["COMPLETE"],"type":"string","enum":["COMPLETE","INCOMPLETE","PENDING"]},"location":{"description":"Centro de trabajo del fichaje.","anyOf":[{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"isModified":{"description":"Se corrigió después de registrarse (queda trazado en la cadena de integridad).","examples":[false],"type":"boolean"},"requiresCorrection":{"description":"Tiene una corrección pendiente o se marcó para revisión.","examples":[false],"type":"boolean"},"offlineCreated":{"description":"Se registró sin conexión en un terminal y se sincronizó después.","examples":[false],"type":"boolean"},"note":{"description":"Nota del empleado.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"adminNote":{"description":"Nota del administrador.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"expected":{"description":"Lo que esperaba el turno asignado cuando se registró el fichaje.","type":"object","properties":{"startTime":{"description":"Entrada prevista por el turno (HH:mm, hora local).","examples":["09:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"endTime":{"description":"Salida prevista (HH:mm, hora local).","examples":["17:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"hours":{"description":"Horas previstas ese día.","examples":[7.5],"anyOf":[{"type":"number"},{"type":"null"}]},"arrivalStatus":{"description":"Puntualidad de la entrada: early | on-time | late | very-late.","examples":["on-time"],"anyOf":[{"type":"string"},{"type":"null"}]},"minutesLate":{"description":"Minutos de retraso (negativo = llegó antes).","examples":[-2],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"departureStatus":{"description":"Puntualidad de la salida: early | on-time.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"minutesEarly":{"description":"Minutos que salió antes de la hora.","examples":[null],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["startTime","endTime","hours","arrivalStatus","minutesLate","departureStatus","minutesEarly"],"additionalProperties":false},"createdAt":{"description":"Cuándo se guardó (UTC). Puede ser posterior a timestamp si llegó sin conexión.","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC). Es la marca de la sincronización incremental.","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"deletedAt":{"description":"Eliminado (UTC), o null.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","employeeId","type","timestamp","shiftDate","method","source","status","location","isModified","requiresCorrection","offlineCreated","note","adminNote","expected","createdAt","updatedAt","deletedAt"],"additionalProperties":false},"WorkSession":{"type":"object","properties":{"object":{"type":"string","const":"workSession"},"employeeId":{"description":"Empleado.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"shiftDate":{"description":"Día de jornada (YYYY-MM-DD, zona de la empresa).","examples":["2026-09-15"],"type":"string"},"dayType":{"description":"Tipo de día según el calendario.","examples":["WORKING"],"type":"string","enum":["WORKING","HOLIDAY","REST"]},"status":{"description":"ABSENT = día laborable sin fichajes ni ausencia; INCOMPLETE = falta una entrada o una salida (revísalo antes de cerrar la nómina).","examples":["COMPLETE"],"type":"string","enum":["COMPLETE","INCOMPLETE","ABSENT","LEAVE","HOLIDAY","REST"]},"scheduleSource":{"description":"De dónde sale la jornada prevista: turno, horario del empleado, del centro, de la empresa…","examples":["SHIFT"],"type":"string","enum":["SHIFT","EMPLOYEE_SCHEDULE","LOCATION","COMPANY","CALCULATED","HOLIDAY","LEAVE","NONE"]},"firstIn":{"description":"Primera entrada del día (UTC).","examples":["2026-09-15T06:58:31.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"lastOut":{"description":"Última salida del día (UTC).","examples":["2026-09-15T15:02:10.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"segments":{"description":"Tramos de trabajo emparejados (IN → OUT), en orden.","examples":[[{"in":"2026-09-15T06:58:31.000Z","out":"2026-09-15T11:00:02.000Z","entryIds":[918273,918280],"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"}},{"in":"2026-09-15T11:30:15.000Z","out":"2026-09-15T15:02:10.000Z","entryIds":[918283,918290],"location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"}}]],"type":"array","items":{"type":"object","properties":{"in":{"description":"Entrada del tramo (UTC); null si falta.","examples":["2026-09-15T06:58:31.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"out":{"description":"Salida del tramo (UTC); null si sigue abierto o falta.","examples":["2026-09-15T11:00:02.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"entryIds":{"description":"Fichajes que forman el tramo.","examples":[[918273,918280]],"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"location":{"description":"Centro del tramo.","anyOf":[{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["in","out","entryIds","location"],"additionalProperties":false}},"breaks":{"description":"Pausas fichadas.","type":"array","items":{"type":"object","properties":{"start":{"description":"Inicio de la pausa (UTC).","examples":["2026-09-15T11:00:02.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"end":{"description":"Fin de la pausa (UTC); null si sigue abierta.","examples":["2026-09-15T11:30:15.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"entryIds":{"description":"Fichajes BREAK_START y BREAK_END de la pausa.","examples":[[918281,918282]],"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}},"required":["start","end","entryIds"],"additionalProperties":false}},"workedMinutes":{"description":"Minutos computados como trabajados: lo fichado, más las pausas retribuidas y las ausencias que computan.","examples":[453],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"workedTime":{"description":"workedMinutes en HH:mm.","examples":["07:33"],"type":"string"},"clockedMinutes":{"description":"Parte de workedMinutes que sale de los fichajes.","examples":[453],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"breakMinutes":{"description":"Minutos de pausa.","examples":[30],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidBreakMinutes":{"description":"De ellos, retribuidos (cuentan como trabajo).","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"autoDeductedBreakMinutes":{"description":"Pausa del turno descontada aunque no se fichara.","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignedMinutes":{"description":"Jornada prevista en minutos.","examples":[450],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignedTime":{"description":"assignedMinutes en HH:mm.","examples":["07:30"],"type":"string"},"balanceMinutes":{"description":"workedMinutes − assignedMinutes. Negativo = faltan minutos.","examples":[3],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"balanceTime":{"description":"balanceMinutes en HH:mm (con signo).","examples":["00:03"],"type":"string"},"leaves":{"description":"Ausencias aprobadas que cubren el día (vacío si no hay).","examples":[[]],"type":"array","items":{"type":"object","properties":{"leaveRequestId":{"description":"Id de la ausencia.","examples":["cm1lr5q2w0009qx4m7c3z8k1m"],"type":"string"},"leaveTypeCode":{"description":"Código del tipo de ausencia. `RESTRICTED` si es de salud (baja, consulta médica…) y la clave no tiene employees:read_pii.","examples":["MEDICAL"],"type":"string"},"leaveTypeName":{"description":"Nombre del tipo («Ausencia» si está reservado).","examples":["Consulta médica"],"type":"string"},"isPaid":{"description":"Computa como tiempo trabajado.","examples":[true],"type":"boolean"},"unit":{"description":"Por días o por horas.","examples":["HOURS"],"type":"string","enum":["DAYS","HOURS"]},"hours":{"description":"Horas de la ausencia ese día (por horas).","examples":[2],"anyOf":[{"type":"number"},{"type":"null"}]},"halfDay":{"description":"MORNING | AFTERNOON en medios días.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["leaveRequestId","leaveTypeCode","leaveTypeName","isPaid","unit","hours","halfDay"],"additionalProperties":false}},"isModified":{"description":"Algún fichaje del día se corrigió.","examples":[false],"type":"boolean"},"requiresCorrection":{"description":"Algún fichaje del día está pendiente de revisión.","examples":[false],"type":"boolean"},"hasOpenSegment":{"description":"El día acaba con una entrada sin salida.","examples":[false],"type":"boolean"},"engine":{"description":"Motor que produjo las cifras. Si cambia, el changelog de la API lo explica.","examples":["hours_balance_v1"],"type":"string"}},"required":["object","employeeId","shiftDate","dayType","status","scheduleSource","firstIn","lastOut","segments","breaks","workedMinutes","workedTime","clockedMinutes","breakMinutes","paidBreakMinutes","autoDeductedBreakMinutes","assignedMinutes","assignedTime","balanceMinutes","balanceTime","leaves","isModified","requiresCorrection","hasOpenSegment","engine"],"additionalProperties":false},"ClockAction":{"type":"object","properties":{"object":{"type":"string","const":"clockAction"},"action":{"description":"Lo que se ha registrado.","examples":["IN"],"type":"string","enum":["IN","OUT","BREAK_START","BREAK_END"]},"state":{"description":"Estado del empleado después del fichaje: úsalo para pintar la pantalla.","examples":["working"],"type":"string","enum":["working","off","on_break"]},"entry":{"description":"El fichaje principal (un ClockEntry).","examples":[{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null}],"type":"object","properties":{"object":{"type":"string","const":"clockEntry"},"id":{"description":"Id del fichaje.","examples":[918273],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"employeeId":{"description":"Empleado que fichó.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"type":{"description":"IN = entrada · OUT = salida · BREAK_START / BREAK_END = inicio y fin de pausa.","examples":["IN"],"type":"string","enum":["IN","OUT","BREAK_START","BREAK_END"]},"timestamp":{"description":"Instante del fichaje en UTC (la hora oficial, la del servidor).","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"shiftDate":{"description":"Día de jornada en la zona horaria de la empresa. Un turno de noche que sale de madrugada conserva el día de la entrada.","examples":["2026-09-15"],"type":"string"},"method":{"description":"Canal por el que se fichó.","examples":["APP"],"type":"string","enum":["WEB","APP","QR","KIOSK","SLACK","WHATSAPP","API"]},"source":{"description":"Origen técnico: WEB | MOBILE | KIOSK | SLACK | WHATSAPP | API.","examples":["MOBILE"],"type":"string"},"status":{"description":"INCOMPLETE = la jornada se quedó sin cerrar y la marcó el sistema.","examples":["COMPLETE"],"type":"string","enum":["COMPLETE","INCOMPLETE","PENDING"]},"location":{"description":"Centro de trabajo del fichaje.","anyOf":[{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"isModified":{"description":"Se corrigió después de registrarse (queda trazado en la cadena de integridad).","examples":[false],"type":"boolean"},"requiresCorrection":{"description":"Tiene una corrección pendiente o se marcó para revisión.","examples":[false],"type":"boolean"},"offlineCreated":{"description":"Se registró sin conexión en un terminal y se sincronizó después.","examples":[false],"type":"boolean"},"note":{"description":"Nota del empleado.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"adminNote":{"description":"Nota del administrador.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"expected":{"description":"Lo que esperaba el turno asignado cuando se registró el fichaje.","type":"object","properties":{"startTime":{"description":"Entrada prevista por el turno (HH:mm, hora local).","examples":["09:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"endTime":{"description":"Salida prevista (HH:mm, hora local).","examples":["17:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"hours":{"description":"Horas previstas ese día.","examples":[7.5],"anyOf":[{"type":"number"},{"type":"null"}]},"arrivalStatus":{"description":"Puntualidad de la entrada: early | on-time | late | very-late.","examples":["on-time"],"anyOf":[{"type":"string"},{"type":"null"}]},"minutesLate":{"description":"Minutos de retraso (negativo = llegó antes).","examples":[-2],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"departureStatus":{"description":"Puntualidad de la salida: early | on-time.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"minutesEarly":{"description":"Minutos que salió antes de la hora.","examples":[null],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["startTime","endTime","hours","arrivalStatus","minutesLate","departureStatus","minutesEarly"],"additionalProperties":false},"createdAt":{"description":"Cuándo se guardó (UTC). Puede ser posterior a timestamp si llegó sin conexión.","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC). Es la marca de la sincronización incremental.","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"deletedAt":{"description":"Eliminado (UTC), o null.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","employeeId","type","timestamp","shiftDate","method","source","status","location","isModified","requiresCorrection","offlineCreated","note","adminNote","expected","createdAt","updatedAt","deletedAt"],"additionalProperties":false},"entries":{"description":"Todos los fichajes creados: las pausas crean dos a la vez (OUT + BREAK_START, o BREAK_END + IN).","examples":[[{"object":"clockEntry","id":918273,"employeeId":4821,"type":"IN","timestamp":"2026-09-15T06:58:31.000Z","shiftDate":"2026-09-15","method":"API","source":"API","status":"COMPLETE","location":{"id":"cm1loczgz0001qx8f2k9d7h3a","name":"Oficina Zaragoza"},"isModified":false,"requiresCorrection":false,"offlineCreated":false,"note":null,"adminNote":null,"expected":{"startTime":"09:00","endTime":"17:00","hours":7.5,"arrivalStatus":"on-time","minutesLate":-2,"departureStatus":null,"minutesEarly":null},"createdAt":"2026-09-15T06:58:31.000Z","updatedAt":"2026-09-15T06:58:31.000Z","deletedAt":null}]],"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"clockEntry"},"id":{"description":"Id del fichaje.","examples":[918273],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"employeeId":{"description":"Empleado que fichó.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"type":{"description":"IN = entrada · OUT = salida · BREAK_START / BREAK_END = inicio y fin de pausa.","examples":["IN"],"type":"string","enum":["IN","OUT","BREAK_START","BREAK_END"]},"timestamp":{"description":"Instante del fichaje en UTC (la hora oficial, la del servidor).","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"shiftDate":{"description":"Día de jornada en la zona horaria de la empresa. Un turno de noche que sale de madrugada conserva el día de la entrada.","examples":["2026-09-15"],"type":"string"},"method":{"description":"Canal por el que se fichó.","examples":["APP"],"type":"string","enum":["WEB","APP","QR","KIOSK","SLACK","WHATSAPP","API"]},"source":{"description":"Origen técnico: WEB | MOBILE | KIOSK | SLACK | WHATSAPP | API.","examples":["MOBILE"],"type":"string"},"status":{"description":"INCOMPLETE = la jornada se quedó sin cerrar y la marcó el sistema.","examples":["COMPLETE"],"type":"string","enum":["COMPLETE","INCOMPLETE","PENDING"]},"location":{"description":"Centro de trabajo del fichaje.","anyOf":[{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"isModified":{"description":"Se corrigió después de registrarse (queda trazado en la cadena de integridad).","examples":[false],"type":"boolean"},"requiresCorrection":{"description":"Tiene una corrección pendiente o se marcó para revisión.","examples":[false],"type":"boolean"},"offlineCreated":{"description":"Se registró sin conexión en un terminal y se sincronizó después.","examples":[false],"type":"boolean"},"note":{"description":"Nota del empleado.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"adminNote":{"description":"Nota del administrador.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"expected":{"description":"Lo que esperaba el turno asignado cuando se registró el fichaje.","type":"object","properties":{"startTime":{"description":"Entrada prevista por el turno (HH:mm, hora local).","examples":["09:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"endTime":{"description":"Salida prevista (HH:mm, hora local).","examples":["17:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"hours":{"description":"Horas previstas ese día.","examples":[7.5],"anyOf":[{"type":"number"},{"type":"null"}]},"arrivalStatus":{"description":"Puntualidad de la entrada: early | on-time | late | very-late.","examples":["on-time"],"anyOf":[{"type":"string"},{"type":"null"}]},"minutesLate":{"description":"Minutos de retraso (negativo = llegó antes).","examples":[-2],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"departureStatus":{"description":"Puntualidad de la salida: early | on-time.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"minutesEarly":{"description":"Minutos que salió antes de la hora.","examples":[null],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["startTime","endTime","hours","arrivalStatus","minutesLate","departureStatus","minutesEarly"],"additionalProperties":false},"createdAt":{"description":"Cuándo se guardó (UTC). Puede ser posterior a timestamp si llegó sin conexión.","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC). Es la marca de la sincronización incremental.","examples":["2026-09-15T06:58:31.000Z"],"type":"string"},"deletedAt":{"description":"Eliminado (UTC), o null.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","employeeId","type","timestamp","shiftDate","method","source","status","location","isModified","requiresCorrection","offlineCreated","note","adminNote","expected","createdAt","updatedAt","deletedAt"],"additionalProperties":false}},"idempotentReplay":{"description":"true si es la respuesta repetida de un Idempotency-Key ya usado (no se ha fichado otra vez).","examples":[false],"type":"boolean"}},"required":["object","action","state","entry","entries","idempotentReplay"],"additionalProperties":false},"ClockCorrection":{"type":"object","properties":{"object":{"type":"string","const":"clockCorrection"},"id":{"description":"Id de la solicitud.","examples":["cm1corr8k2p0007qx3n5v1b9d"],"type":"string"},"employeeId":{"description":"Empleado del fichaje.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"clockEntryId":{"description":"Fichaje que corrige (null si propone uno que falta o una jornada completa).","examples":[null],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"requestType":{"description":"MISSING_CLOCK_IN / MISSING_CLOCK_OUT = falta un extremo · INCORRECT_TIME = hora equivocada · MANUAL_FULL_SHIFT = jornada completa olvidada · MANUAL_BREAK = pausa.","examples":["MANUAL_FULL_SHIFT"],"type":"string","enum":["MISSING_CLOCK_IN","MISSING_CLOCK_OUT","INCORRECT_TIME","MANUAL_FULL_SHIFT","MANUAL_BREAK"]},"missingType":{"description":"Extremo que se corrige (null en jornadas y pausas completas).","examples":[null],"anyOf":[{"type":"string","enum":["IN","OUT","BREAK_START","BREAK_END"]},{"type":"null"}]},"proposedTime":{"description":"Hora propuesta (UTC). Null en jornadas y pausas completas: van en `manual`.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"originalTime":{"description":"Hora que tenía el fichaje antes de corregirlo (UTC).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"manual":{"description":"Solo en jornadas y pausas completas: el día y las horas propuestas.","anyOf":[{"type":"object","properties":{"shiftDate":{"description":"Día de la jornada.","examples":["2026-09-14"],"anyOf":[{"description":"YYYY-MM-DD","type":"string"},{"type":"null"}]},"start":{"description":"Entrada propuesta (UTC).","examples":["2026-09-14T07:00:00.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"end":{"description":"Salida propuesta (UTC).","examples":["2026-09-14T15:00:00.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["shiftDate","start","end"],"additionalProperties":false},{"type":"null"}]},"location":{"description":"Centro propuesto para los fichajes.","anyOf":[{"type":"object","properties":{"id":{"description":"Id del centro de trabajo.","examples":["cm1loczgz0001qx8f2k9d7h3a"],"type":"string"},"name":{"description":"Nombre del centro.","examples":["Oficina Zaragoza"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"reason":{"description":"Motivo que dio quien la pidió.","examples":["Olvidé fichar: estuve todo el día en la obra de Valdespartera."],"type":"string"},"status":{"description":"PENDING hasta que una persona la aprueba o la rechaza.","examples":["PENDING"],"type":"string","enum":["PENDING","APPROVED","REJECTED"]},"reviewedAt":{"description":"Cuándo se revisó (UTC).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"reviewedById":{"description":"Administrador que la revisó.","examples":[null],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"rejectionReason":{"description":"Motivo del rechazo (se envía al empleado).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"isAutoApproved":{"description":"Se aprobó en la misma llamada con autoApprove.","examples":[false],"type":"boolean"},"createdAt":{"description":"Cuándo se pidió (UTC).","examples":["2026-09-15T07:05:12.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC).","examples":["2026-09-15T07:05:12.000Z"],"type":"string"}},"required":["object","id","employeeId","clockEntryId","requestType","missingType","proposedTime","originalTime","manual","location","reason","status","reviewedAt","reviewedById","rejectionReason","isAutoApproved","createdAt","updatedAt"],"additionalProperties":false},"LeaveType":{"type":"object","properties":{"object":{"type":"string","const":"leaveType"},"id":{"description":"Id del tipo de ausencia.","examples":["cm1ltvac0001qx7d2k8f4h6jk"],"type":"string"},"code":{"description":"Identificador estable para integrar (configurable por empresa): usa este, no el nombre.","examples":["VACATION"],"type":"string"},"name":{"description":"Nombre visible.","examples":["Vacaciones"],"type":"string"},"description":{"description":"Descripción que ve el empleado.","examples":["Vacaciones anuales retribuidas."],"anyOf":[{"type":"string"},{"type":"null"}]},"color":{"description":"Color en el calendario (hex).","examples":["#3B82F6"],"type":"string"},"unit":{"description":"Se pide por días o por horas.","examples":["DAYS"],"type":"string","enum":["DAYS","HOURS"]},"dayCountType":{"description":"Qué días cuenta: laborables o naturales.","examples":["BUSINESS_DAYS"],"type":"string","enum":["BUSINESS_DAYS","NATURAL_DAYS"]},"requiresBalance":{"description":"Consume un cupo anual (ver GET /v1/leave-balances).","examples":[true],"type":"boolean"},"requiresApproval":{"description":"Necesita aprobación; si no, nace aprobada.","examples":[true],"type":"boolean"},"requiresDocument":{"description":"Pide justificante.","examples":[false],"type":"boolean"},"requiresReason":{"description":"Pide motivo.","examples":[false],"type":"boolean"},"allowHalfDays":{"description":"Admite medios días.","examples":[true],"type":"boolean"},"isPaid":{"description":"Computa como tiempo trabajado.","examples":[true],"type":"boolean"},"blockClocking":{"description":"Impide fichar esos días.","examples":[true],"type":"boolean"},"affectsWorkingDays":{"description":"Descuenta la jornada prevista de esos días.","examples":[true],"type":"boolean"},"isActive":{"description":"Se puede usar al crear ausencias.","examples":[true],"type":"boolean"},"isSystem":{"description":"Tipo de sistema (p. ej. descanso compensatorio de la bolsa de horas): se lee, no se usa al crear.","examples":[false],"type":"boolean"},"createdAt":{"description":"Alta (UTC).","examples":["2025-01-08T11:20:00.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC).","examples":["2026-01-02T09:00:00.000Z"],"type":"string"}},"required":["object","id","code","name","description","color","unit","dayCountType","requiresBalance","requiresApproval","requiresDocument","requiresReason","allowHalfDays","isPaid","blockClocking","affectsWorkingDays","isActive","isSystem","createdAt","updatedAt"],"additionalProperties":false},"LeaveRequest":{"type":"object","properties":{"object":{"type":"string","const":"leaveRequest"},"id":{"description":"Id de la ausencia.","examples":["cm1lr5q2w0009qx4m7c3z8k1m"],"type":"string"},"employeeId":{"description":"Empleado.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"leaveType":{"description":"Tipo de ausencia. Los de salud (bajas, IT, consultas médicas…) son datos sensibles: solo con employees:read_pii.","type":"object","properties":{"id":{"description":"Id del tipo de ausencia. null cuando el tipo está reservado (ver `code`).","examples":["cm1ltvac0001qx7d2k8f4h6jk"],"anyOf":[{"type":"string"},{"type":"null"}]},"code":{"description":"Código estable del tipo: integra por él. `RESTRICTED` si es un tipo de salud (baja, consulta médica…) y la clave no tiene employees:read_pii.","examples":["VACATION"],"type":"string"},"name":{"description":"Nombre del tipo («Ausencia» si está reservado).","examples":["Vacaciones"],"type":"string"}},"required":["id","code","name"],"additionalProperties":false},"unit":{"description":"Por días o por horas.","examples":["DAYS"],"type":"string","enum":["DAYS","HOURS"]},"startDate":{"description":"Primer día (YYYY-MM-DD).","examples":["2026-10-13"],"type":"string"},"endDate":{"description":"Último día (YYYY-MM-DD), inclusive.","examples":["2026-10-16"],"type":"string"},"startHalf":{"description":"Medio día al inicio, si lo hay.","examples":[null],"anyOf":[{"type":"string","enum":["MORNING","AFTERNOON"]},{"type":"null"}]},"endHalf":{"description":"Medio día al final, si lo hay.","examples":[null],"anyOf":[{"type":"string","enum":["MORNING","AFTERNOON"]},{"type":"null"}]},"startTime":{"description":"Hora de inicio (HH:mm, hora local), solo en ausencias por horas.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"endTime":{"description":"Hora de fin (HH:mm, hora local), solo en ausencias por horas.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"hours":{"description":"Horas, solo en ausencias por horas.","examples":[null],"anyOf":[{"type":"number"},{"type":"null"}]},"businessDays":{"description":"Días que consume (0,5 en medios días; 0 en ausencias por horas).","examples":[4],"type":"number"},"status":{"description":"Estado de la solicitud.","examples":["APPROVED"],"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED"]},"source":{"description":"Quién la registró: el empleado, un administrador, la API o el sistema.","examples":["API"],"type":"string","enum":["EMPLOYEE","ADMIN","API","SYSTEM"]},"reason":{"description":"Motivo que dio el empleado. Es texto libre y puede contener datos de salud: solo con employees:read_pii (sin él, null).","examples":["Puente del Pilar"],"anyOf":[{"type":"string"},{"type":"null"}]},"reviewedAt":{"description":"Cuándo se revisó (UTC).","examples":["2026-09-16T08:02:40.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"reviewedById":{"description":"Administrador que la revisó.","examples":[17],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"rejectionReason":{"description":"Motivo del rechazo. Texto libre: solo con employees:read_pii (sin él, null).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"cancelledAt":{"description":"Cuándo se canceló (UTC).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"description":"Cuándo se pidió (UTC).","examples":["2026-09-15T16:20:03.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC). Es la marca de la sincronización incremental.","examples":["2026-09-16T08:02:40.000Z"],"type":"string"}},"required":["object","id","employeeId","leaveType","unit","startDate","endDate","startHalf","endHalf","startTime","endTime","hours","businessDays","status","source","reason","reviewedAt","reviewedById","rejectionReason","cancelledAt","createdAt","updatedAt"],"additionalProperties":false},"LeaveBalance":{"type":"object","properties":{"object":{"type":"string","const":"leaveBalance"},"employeeId":{"description":"Empleado.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"leaveType":{"description":"Tipo de ausencia del cupo.","type":"object","properties":{"id":{"description":"Id del tipo de ausencia.","examples":["cm1ltvac0001qx7d2k8f4h6jk"],"type":"string"},"code":{"description":"Código estable del tipo: integra por él.","examples":["VACATION"],"type":"string"},"name":{"description":"Nombre del tipo.","examples":["Vacaciones"],"type":"string"}},"required":["id","code","name"],"additionalProperties":false},"year":{"description":"Año del cupo.","examples":[2026],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unit":{"description":"Unidad de todas las cifras: días u horas.","examples":["DAYS"],"type":"string","enum":["DAYS","HOURS"]},"allocated":{"description":"Asignado para el año.","examples":[22],"type":"number"},"carryOver":{"description":"Arrastrado del año anterior.","examples":[2],"type":"number"},"adjustment":{"description":"Ajustes manuales del administrador (positivos o negativos).","examples":[0],"type":"number"},"used":{"description":"Consumido o reservado por ausencias pendientes y aprobadas.","examples":[12],"type":"number"},"available":{"description":"Disponible: asignado + arrastrado + ajustes − consumido.","examples":[12],"type":"number"},"carriedFromPreviousYears":{"description":"Deuda arrastrada de años anteriores (negativa o 0).","examples":[0],"type":"number"}},"required":["object","employeeId","leaveType","year","unit","allocated","carryOver","adjustment","used","available","carriedFromPreviousYears"],"additionalProperties":false},"HoursBalance":{"type":"object","properties":{"object":{"type":"string","const":"hoursBalance"},"employeeId":{"description":"Empleado.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"from":{"description":"Primer día del periodo.","examples":["2026-09-01"],"type":"string"},"to":{"description":"Último día del periodo.","examples":["2026-09-30"],"type":"string"},"workedMinutes":{"description":"Minutos trabajados en el periodo (con pausas retribuidas y ausencias que computan).","examples":[9540],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"workedTime":{"description":"workedMinutes en HH:mm (las horas pueden pasar de 24).","examples":["159:00"],"type":"string"},"assignedMinutes":{"description":"Minutos previstos por la jornada en el periodo.","examples":[9450],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignedTime":{"description":"assignedMinutes en HH:mm.","examples":["157:30"],"type":"string"},"balanceMinutes":{"description":"Trabajado − previsto. Positivo = minutos de más; negativo = faltan.","examples":[90],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"balanceTime":{"description":"balanceMinutes en HH:mm (con signo).","examples":["01:30"],"type":"string"},"breakMinutes":{"description":"Minutos de pausa.","examples":[630],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidBreakMinutes":{"description":"De ellos, retribuidos.","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"autoDeductedMinutes":{"description":"Pausas del turno descontadas aunque no se ficharan.","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"daysWorked":{"description":"Días con tiempo trabajado.","examples":[21],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"daysWithOpenSegment":{"description":"Días que acaban con una entrada sin salida. Si no es 0, revísalos antes de cerrar la nómina.","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["object","employeeId","from","to","workedMinutes","workedTime","assignedMinutes","assignedTime","balanceMinutes","balanceTime","breakMinutes","paidBreakMinutes","autoDeductedMinutes","daysWorked","daysWithOpenSegment"],"additionalProperties":false},"HoursBalanceDay":{"type":"object","properties":{"object":{"type":"string","const":"hoursBalanceDay"},"employeeId":{"description":"Empleado.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"date":{"description":"Día de jornada.","examples":["2026-09-15"],"type":"string"},"clockIn":{"description":"Primera entrada del día, HH:mm en hora local.","examples":["08:58"],"anyOf":[{"type":"string"},{"type":"null"}]},"clockOut":{"description":"Última salida del día, HH:mm en hora local.","examples":["17:02"],"anyOf":[{"type":"string"},{"type":"null"}]},"workedMinutes":{"description":"Minutos trabajados.","examples":[453],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignedMinutes":{"description":"Minutos previstos.","examples":[450],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"balanceMinutes":{"description":"Trabajado − previsto.","examples":[3],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"breakMinutes":{"description":"Minutos de pausa.","examples":[30],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidBreakMinutes":{"description":"De ellos, retribuidos.","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"autoDeductedMinutes":{"description":"Pausa del turno descontada aunque no se fichara.","examples":[0],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scheduleSource":{"description":"De dónde sale la jornada prevista: es lo primero que mirar cuando no cuadran las horas.","examples":["SHIFT"],"type":"string","enum":["SHIFT","EMPLOYEE_SCHEDULE","LOCATION","COMPANY","CALCULATED","HOLIDAY","LEAVE","NONE"]},"hasOpenSegment":{"description":"El día acaba con una entrada sin salida.","examples":[false],"type":"boolean"},"notes":{"description":"Cómo se calculó el día (festivo, permiso, turno…). Texto informativo, no contrato.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","employeeId","date","clockIn","clockOut","workedMinutes","assignedMinutes","balanceMinutes","breakMinutes","paidBreakMinutes","autoDeductedMinutes","scheduleSource","hasOpenSegment","notes"],"additionalProperties":false},"Shift":{"type":"object","properties":{"object":{"type":"string","const":"shift"},"id":{"description":"Id del turno.","examples":["cm1shmnn0002qx9p4c6v8b2de"],"type":"string"},"name":{"description":"Nombre del turno.","examples":["Mañana"],"type":"string"},"type":{"description":"WORK = turno de trabajo; FREE = día libre marcado en el calendario.","examples":["WORK"],"type":"string","enum":["WORK","FREE"]},"color":{"description":"Color en el calendario (hex).","examples":["#10B981"],"type":"string"},"isNight":{"description":"Turno de noche (sale al día siguiente).","examples":[false],"type":"boolean"},"isSplit":{"description":"Jornada partida (más de un tramo).","examples":[false],"type":"boolean"},"segments":{"description":"Tramos del turno.","type":"array","items":{"type":"object","properties":{"start":{"description":"Inicio del tramo (HH:mm, hora local).","examples":["09:00"],"type":"string"},"end":{"description":"Fin del tramo (HH:mm, hora local).","examples":["17:00"],"type":"string"}},"required":["start","end"],"additionalProperties":false}},"totalHours":{"description":"Horas de trabajo del turno (sin las pausas no retribuidas).","examples":[7.5],"type":"number"},"applicableDays":{"description":"Días en los que aplica: 0 = domingo … 6 = sábado.","examples":[[1,2,3,4,5]],"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"tolerance":{"description":"Tolerancias de puntualidad.","type":"object","properties":{"entryMinutes":{"description":"Minutos de margen en la entrada antes de marcar retraso.","examples":[10],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"exitMinutes":{"description":"Minutos de margen en la salida.","examples":[10],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["entryMinutes","exitMinutes"],"additionalProperties":false},"breaks":{"description":"Pausas previstas del turno.","type":"array","items":{"type":"object","properties":{"id":{"description":"Id de la pausa.","examples":["cm1brkcm0003qx9p4c6v8b2df"],"type":"string"},"name":{"description":"Nombre.","examples":["Comida"],"type":"string"},"startTime":{"description":"Hora de inicio (HH:mm, hora local).","examples":["13:00"],"type":"string"},"durationMinutes":{"description":"Duración en minutos.","examples":[30],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isPaid":{"description":"Retribuida: cuenta como trabajo.","examples":[false],"type":"boolean"},"autoDeduct":{"description":"Se descuenta aunque no se fiche.","examples":[false],"type":"boolean"}},"required":["id","name","startTime","durationMinutes","isPaid","autoDeduct"],"additionalProperties":false}},"createdAt":{"description":"Alta (UTC).","examples":["2025-02-03T09:30:00.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC).","examples":["2026-03-10T12:00:00.000Z"],"type":"string"}},"required":["object","id","name","type","color","isNight","isSplit","segments","totalHours","applicableDays","tolerance","breaks","createdAt","updatedAt"],"additionalProperties":false},"ShiftAssignment":{"type":"object","properties":{"object":{"type":"string","const":"shiftAssignment"},"employeeId":{"description":"Empleado.","examples":[4821],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"date":{"description":"Día.","examples":["2026-09-15"],"type":"string"},"origin":{"description":"ASSIGNMENT = calendario día a día (manda); PERIOD = turno por rango de fechas; DEFAULT = turno fijo.","examples":["DEFAULT"],"type":"string","enum":["ASSIGNMENT","PERIOD","DEFAULT"]},"shift":{"description":"Turno de ese día (null en un día libre pintado sin turno).","anyOf":[{"type":"object","properties":{"id":{"description":"Id del turno.","examples":["cm1shmnn0002qx9p4c6v8b2de"],"type":"string"},"name":{"description":"Nombre del turno.","examples":["Mañana"],"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"isDayOff":{"description":"Día libre marcado en el calendario.","examples":[false],"type":"boolean"},"startTime":{"description":"Entrada prevista (HH:mm, hora local).","examples":["09:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"endTime":{"description":"Salida prevista (HH:mm, hora local).","examples":["17:00"],"anyOf":[{"type":"string"},{"type":"null"}]},"hours":{"description":"Horas previstas.","examples":[7.5],"anyOf":[{"type":"number"},{"type":"null"}]},"notes":{"description":"Nota del calendario.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","employeeId","date","origin","shift","isDayOff","startTime","endTime","hours","notes"],"additionalProperties":false},"Holiday":{"type":"object","properties":{"object":{"type":"string","const":"holiday"},"id":{"description":"Id del festivo.","examples":["cm1hol12o0004qx2b7n5c9d3f"],"type":"string"},"date":{"description":"Día (YYYY-MM-DD, zona de la empresa).","examples":["2026-10-12"],"type":"string"},"name":{"description":"Nombre.","examples":["Fiesta Nacional de España"],"type":"string"},"type":{"description":"Nacional, autonómico, local o propio de la empresa.","examples":["NATIONAL"],"type":"string","enum":["NATIONAL","REGIONAL","LOCAL","COMPANY"]},"scope":{"description":"COMPANY = de toda la empresa; LOCATION = solo de un centro.","examples":["COMPANY"],"type":"string","enum":["COMPANY","LOCATION"]},"locationId":{"description":"Centro al que aplica (solo con scope LOCATION).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"province":{"description":"Provincia (festivos autonómicos).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"workingHours":{"description":"Horas de trabajo previstas ese día (0 = festivo completo; más = jornada reducida).","examples":[0],"type":"number"},"recurrent":{"description":"Se repite cada año en la misma fecha.","examples":[true],"type":"boolean"}},"required":["object","id","date","name","type","scope","locationId","province","workingHours","recurrent"],"additionalProperties":false},"Export":{"type":"object","properties":{"object":{"type":"string","const":"export"},"id":{"description":"Id de la exportación.","examples":["cm1exp7t0005qx6c3m9b2v8zq"],"type":"string"},"status":{"description":"pending → processing → completed (o failed). expired = el archivo ya se borró.","examples":["completed"],"type":"string","enum":["pending","processing","completed","failed","expired"]},"dataset":{"description":"Informe pedido.","examples":["clocking"],"type":"string","enum":["clocking","balance","absence","hour-bank","location-hours"]},"format":{"description":"Formato del archivo.","examples":["pdf"],"type":"string","enum":["csv","xlsx","pdf"]},"from":{"description":"Primer día del periodo.","examples":["2026-09-01"],"anyOf":[{"description":"YYYY-MM-DD","type":"string"},{"type":"null"}]},"to":{"description":"Último día del periodo.","examples":["2026-09-30"],"anyOf":[{"description":"YYYY-MM-DD","type":"string"},{"type":"null"}]},"progress":{"description":"Progreso, de 0 a 100.","examples":[100],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rows":{"description":"Filas de datos del informe (cuando termina).","examples":[412],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"sizeBytes":{"description":"Tamaño del archivo en bytes.","examples":[183422],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"downloadUrl":{"description":"Solo con status completed. Válida 1 hora: pídela de nuevo a este endpoint cuando la necesites.","examples":["https://api.fichme.com/api/files/eyJqb2IiOiJjbTFleHA3dDAwMDUifQ/registro-jornada-2026-09.pdf"],"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"description":"Qué falló, si status es failed.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"description":"Cuándo se pidió (UTC).","examples":["2026-10-01T07:00:03.000Z"],"type":"string"},"completedAt":{"description":"Cuándo terminó (UTC).","examples":["2026-10-01T07:00:41.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"expiresAt":{"description":"A partir de aquí el archivo se borra (24 h tras crearse).","examples":["2026-10-02T07:00:03.000Z"],"type":"string"}},"required":["object","id","status","dataset","format","from","to","progress","rows","sizeBytes","downloadUrl","error","createdAt","completedAt","expiresAt"],"additionalProperties":false},"WebhookEndpoint":{"type":"object","properties":{"object":{"type":"string","const":"webhookEndpoint"},"id":{"description":"Id del webhook.","examples":["cm1whk4r0006qx8v2n6c3b7xy"],"type":"string"},"url":{"description":"URL https que recibe los eventos.","examples":["https://erp.example.com/webhooks/fichme"],"type":"string"},"description":{"description":"Descripción libre.","examples":["ERP de nóminas"],"anyOf":[{"type":"string"},{"type":"null"}]},"events":{"description":"Tipos suscritos, o [\"*\"] para todos.","examples":[["clockEntry.created","leaveRequest.approved"]],"type":"array","items":{"type":"string"}},"status":{"description":"DISABLED = desactivado automáticamente tras 72 h fallando (reactívalo con PATCH status ACTIVE).","examples":["ACTIVE"],"type":"string","enum":["ACTIVE","PAUSED","DISABLED"]},"failingSince":{"description":"Desde cuándo falla sin interrupción (UTC), o null.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"disabledReason":{"description":"Por qué se desactivó.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"secretLast4":{"description":"Últimos 4 caracteres del secreto, para reconocerlo.","examples":["hJ2l"],"type":"string"},"createdAt":{"description":"Alta (UTC).","examples":["2026-09-10T09:00:00.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC).","examples":["2026-09-10T09:00:00.000Z"],"type":"string"},"lastDelivery":{"description":"La entrega más reciente, o null si aún no hubo ninguna.","anyOf":[{"type":"object","properties":{"status":{"description":"Resultado de la última entrega.","examples":["DELIVERED"],"type":"string","enum":["DELIVERED","FAILED","PENDING"]},"httpStatus":{"description":"Código HTTP que respondió tu servidor.","examples":[200],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"at":{"description":"Cuándo (UTC).","examples":["2026-09-15T06:58:33.000Z"],"type":"string"}},"required":["status","httpStatus","at"],"additionalProperties":false},{"type":"null"}]}},"required":["object","id","url","description","events","status","failingSince","disabledReason","secretLast4","createdAt","updatedAt","lastDelivery"],"additionalProperties":false},"WebhookEndpointWithSecret":{"type":"object","properties":{"endpoint":{"description":"El webhook (WebhookEndpoint).","type":"object","properties":{"object":{"type":"string","const":"webhookEndpoint"},"id":{"description":"Id del webhook.","examples":["cm1whk4r0006qx8v2n6c3b7xy"],"type":"string"},"url":{"description":"URL https que recibe los eventos.","examples":["https://erp.example.com/webhooks/fichme"],"type":"string"},"description":{"description":"Descripción libre.","examples":["ERP de nóminas"],"anyOf":[{"type":"string"},{"type":"null"}]},"events":{"description":"Tipos suscritos, o [\"*\"] para todos.","examples":[["clockEntry.created","leaveRequest.approved"]],"type":"array","items":{"type":"string"}},"status":{"description":"DISABLED = desactivado automáticamente tras 72 h fallando (reactívalo con PATCH status ACTIVE).","examples":["ACTIVE"],"type":"string","enum":["ACTIVE","PAUSED","DISABLED"]},"failingSince":{"description":"Desde cuándo falla sin interrupción (UTC), o null.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"disabledReason":{"description":"Por qué se desactivó.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"secretLast4":{"description":"Últimos 4 caracteres del secreto, para reconocerlo.","examples":["hJ2l"],"type":"string"},"createdAt":{"description":"Alta (UTC).","examples":["2026-09-10T09:00:00.000Z"],"type":"string"},"updatedAt":{"description":"Último cambio (UTC).","examples":["2026-09-10T09:00:00.000Z"],"type":"string"},"lastDelivery":{"description":"La entrega más reciente, o null si aún no hubo ninguna.","anyOf":[{"type":"object","properties":{"status":{"description":"Resultado de la última entrega.","examples":["DELIVERED"],"type":"string","enum":["DELIVERED","FAILED","PENDING"]},"httpStatus":{"description":"Código HTTP que respondió tu servidor.","examples":[200],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"at":{"description":"Cuándo (UTC).","examples":["2026-09-15T06:58:33.000Z"],"type":"string"}},"required":["status","httpStatus","at"],"additionalProperties":false},{"type":"null"}]}},"required":["object","id","url","description","events","status","failingSince","disabledReason","secretLast4","createdAt","updatedAt","lastDelivery"],"additionalProperties":false},"secret":{"description":"whsec_…: se muestra UNA sola vez. Guárdalo y úsalo completo, prefijo incluido, para verificar FichMe-Signature.","examples":["whsec_q9Xv2LmT7pR4sW8zN1bK6cY3fH0dJ5gA2eU7iO4hJ2l"],"type":"string"}},"required":["endpoint","secret"],"additionalProperties":false},"WebhookDelivery":{"type":"object","properties":{"object":{"type":"string","const":"webhookDelivery"},"id":{"description":"Id de la entrega.","examples":["48213"],"type":"string"},"eventId":{"description":"Id del evento (el `id` del cuerpo): deduplica por él.","examples":["evt_01K5Q8Z3M2X7C9V4B6N1P8R0TQ"],"type":"string"},"eventType":{"description":"Tipo de evento.","examples":["clockEntry.created"],"type":"string"},"status":{"description":"DELIVERED = tu servidor respondió 2xx; FAILED = se agotaron los intentos.","examples":["DELIVERED"],"type":"string","enum":["DELIVERED","FAILED","PENDING"]},"attempts":{"description":"Intentos hechos.","examples":[1],"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastStatus":{"description":"Código HTTP del último intento.","examples":[200],"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"lastError":{"description":"Error del último intento (timeout, TLS…).","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"description":"Cuándo se generó el evento (UTC).","examples":["2026-09-15T06:58:32.000Z"],"type":"string"},"deliveredAt":{"description":"Cuándo se entregó (UTC).","examples":["2026-09-15T06:58:33.000Z"],"anyOf":[{"type":"string"},{"type":"null"}]},"nextAttemptAt":{"description":"Próximo reintento (UTC), si queda alguno.","examples":[null],"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","eventId","eventType","status","attempts","lastStatus","lastError","createdAt","deliveredAt","nextAttemptAt"],"additionalProperties":false},"WebhookPing":{"type":"object","properties":{"deliveryId":{"description":"Entrega de la prueba: consulta su resultado en el historial de entregas.","examples":["48214"],"type":"string"}},"required":["deliveryId"],"additionalProperties":false}}},"x-scopes":{"company:read":"Datos de la empresa, ajustes básicos y centros de trabajo","employees:read":"Plantilla (datos laborales, sin DNI ni nº de la Seguridad Social)","employees:read_pii":"Datos sensibles: DNI, número de la Seguridad Social y datos de salud (bajas y consultas médicas, motivos de las ausencias); también identificar o dar de alta a un empleado por su DNI","employees:write":"Alta, edición y baja de empleados","clock:read":"Fichajes y jornadas calculadas","clock:write":"Registrar fichajes en tiempo real (requiere activarlo en la empresa)","corrections:read":"Solicitudes de corrección de fichajes","corrections:write":"Crear solicitudes de corrección de fichajes","corrections:manage":"Aprobar o rechazar correcciones de fichajes","absences:read":"Ausencias, tipos de ausencia y saldos","absences:write":"Crear y cancelar ausencias","absences:manage":"Aprobar o rechazar ausencias","balance:read":"Balance de horas (previstas frente a trabajadas)","schedule:read":"Turnos, asignaciones de turno y festivos","exports:read":"Consultar y descargar exportaciones","exports:write":"Lanzar exportaciones (informes en CSV, XLSX o PDF)","webhooks:manage":"Gestionar los webhooks de la empresa"}}