Conecta tu sistema con la asistencia de Huminy
Esta API permite que un PMS, un sistema de nómina, un ERP o un reloj checador físico registren marcaciones, consulten jornadas y sepan quién está en turno. Todos los registros que entran por aquí quedan en la misma bitácora inmutable con folio, huella SHA-256 encadenada y auditoría que usa la app.
/api/public/attendance/eventsRegistrar marcación/api/public/attendance/summariesResúmenes de jornada/api/public/attendance/eligibilityQuién está en turno1. Alta del cliente de integración
En Control de Asistencia → Integraciones, un usuario con rol RH o Admin técnico crea una app y obtiene:
client_id— identificador público del sistema externo.client_secret— se muestra una sola vez; Huminy solo guarda su hash y los últimos 4 caracteres.- Alcances:
attendance:writepara enviar marcaciones yattendance:readpara consultar jornadas y elegibilidad.
Cada llamada queda registrada con endpoint, estatus, IP y cliente en la bitácora de API, visible para RH.
2. Autenticación con firma HMAC
Toda petición lleva tres encabezados:
x-huminy-client-id: hmy_live_xxxxxxxx
x-huminy-timestamp: 1755523200000 # epoch en MILISEGUNDOS (± 5 min)
x-huminy-signature: sha256=<hmac_hex>La firma es HMAC-SHA256(client_secret, `$${timestamp}.$${payload}`) en hexadecimal. El payload es el cuerpo crudo en POST, o el query string sin ? en GET. Un cuerpo distinto al firmado invalida la petición.
// Node.js
import crypto from "node:crypto";
function sign(secret, payload) {
const ts = Date.now(); // milisegundos
const hmac = crypto.createHmac("sha256", secret).update(ts + "." + payload).digest("hex");
return { ts, signature: "sha256=" + hmac };
}
const body = JSON.stringify({ employee_number: "1042", event_type: "clock_in" });
const { ts, signature } = sign(process.env.HUMINY_SECRET, body);
await fetch("https://huminy.app/api/public/attendance/events", {
method: "POST",
headers: {
"content-type": "application/json",
"x-huminy-client-id": process.env.HUMINY_CLIENT_ID,
"x-huminy-timestamp": String(ts),
"x-huminy-signature": signature,
"idempotency-key": crypto.randomUUID(),
},
body,
});3. POST /api/public/attendance/events
Registra una marcación. Requiere alcance attendance:write. Envía idempotency-key para poder reintentar sin duplicar.
{
"employee_number": "1042", // requerido
"event_type": "clock_in", // clock_in | clock_out | break_start | break_end
"device_time": "2026-08-18T07:02:11-05:00",
"latitude": 21.1619,
"longitude": -86.8515,
"method": "reloj_checador",
"external_device_id": "RC-LOBBY-01"
}Respuesta 201:
{
"folio": "ALD-2026-000842",
"event_type": "clock_in",
"server_time": "2026-08-18T12:02:14.221Z",
"validation_result": "valido", // valido | fuera_de_geocerca | retardo | ...
"work_date": "2026-08-18",
"timezone": "America/Cancun"
}Errores: 401 firma inválida o vencida, 403 alcance insuficiente, 404 colaborador no encontrado, 409 secuencia inválida (por ejemplo salida sin entrada), 422 campos inválidos.
4. GET /api/public/attendance/summaries
Resúmenes diarios calculados: horas trabajadas, descansos, retardos y tiempo extra. Ideal para nómina. Requiere attendance:read.
GET https://huminy.app/api/public/attendance/summaries?from=2026-08-01&to=2026-08-15
{
"from": "2026-08-01", "to": "2026-08-15", "count": 210,
"items": [{
"employee_number": "1042",
"work_date": "2026-08-01",
"first_in": "2026-08-01T12:02:14Z",
"last_out": "2026-08-01T20:05:03Z",
"worked_minutes": 452, "break_minutes": 30,
"late_minutes": 2, "overtime_minutes": 12,
"status": "completa"
}]
}5. GET /api/public/attendance/eligibility
Responde si un colaborador puede recibir trabajo ahora mismo: está activo, en turno, presente y sin excepción de calendario. Úsalo antes de asignar una habitación, una tarea o un servicio. Requiere attendance:read.
Parámetros opcionales: employee_number, person_id o external_id (ID estable de tu aplicación, nunca el nombre), work_center_id, expected_work_center_id (para detectar centro equivocado), process (p. ej. opc, liner, closer) y limit (máx. 200).
GET https://huminy.app/api/public/attendance/eligibility?employee_number=1042
{
"checked_at": "2026-08-18T13:20:00.000Z",
"count": 1,
"items": [{
"employee_number": "1042",
"full_name": "Mariana López",
"work_center": { "id": "…", "name": "Hotel Aldea Cancún" },
"timezone": "America/Cancun",
"work_date": "2026-08-18",
"eligible": true,
"codes": [], // ver lista de códigos abajo
"recommended_action": "allow", // allow | warn | require_supervisor | block
"presence": "presente", // sin_registro | presente | en_descanso | salida_registrada
"on_shift": true,
"reason": "Disponible en turno",
"shift": { "name": "Matutino", "start_time": "07:00:00", "end_time": "15:00:00", "crosses_midnight": false },
"last_event": { "type": "clock_in", "at": "2026-08-18T12:02:14Z" },
"exception": null
}]
}La respuesta nunca se cachea. Cuando eligible es false, el campo codes explica por qué:
EMPLOYMENT_INACTIVErelación laboral inactiva ·NO_HUMINY_LINKel ID externo no está vinculadoNO_CLOCK_INsin entrada ·OUTSIDE_SHIFTfuera de turno ·ON_BREAKen pausaWRONG_WORK_CENTERregistró en otro centro ·OPEN_INCIDENTincidencia abiertaPENDING_SYNC(informativo) terminal con registros por sincronizar ·APPROVED_EXCEPTION(informativo) excepción autorizada vigentePROVIDER_UNAVAILABLEHuminy no pudo responder (HTTP 503). Si no obtienes respuesta, tu app debe asumir este código.
Contingencia. RH configura por aplicación, y opcionalmente por proceso, qué hacer cuando la persona no es elegible o Huminy no responde: fail_open (informativo), fail_with_warning (advertencia), require_supervisor o fail_closed (estricto). La respuesta trae el modo vigente en contingency_mode y la acción sugerida en recommended_action; tu aplicación decide. Recomendación para TimeShareFy: guarda en caché el último modo recibido y, ante una caída, aplícalo localmente para no perder una venta.
6. Webhooks salientes
Huminy también puede avisar a tu sistema cuando ocurre algo. Registra una suscripción con la URL destino y los eventos que te interesan; cada entrega se firma igual que las peticiones entrantes y se reintenta ante fallos.
POST https://tu-sistema.com/hooks/huminy
x-huminy-event: attendance.clock_in
x-huminy-event-id: 6f1c… // único por evento; se conserva en reenvíos
x-huminy-timestamp: 1793182800000 // epoch ms
x-huminy-signature: sha256=<hmac>[,sha256=<hmac con secreto anterior>]
{
"event_id": "6f1c…",
"event": "attendance.clock_in",
"sent_at": "2026-10-29T13:00:00.000Z",
"data": { "employee_number": "1042", "event_type": "clock_in", "folio": "ALD-2026-000899" }
}Cómo verificar:
- Calcula
HMAC-SHA256(secreto, timestamp + "." + cuerpo_crudo)y compáralo (en tiempo constante) con cualquiera de las firmas del encabezado. - Rechaza si
x-huminy-timestampdifiere más de 5 minutos de tu reloj (prevención de repetición). - Guarda el
event_idy descarta duplicados (idempotencia; los reenvíos manuales reutilizan el mismo ID). - Responde
2xxrápido. Cualquier otra respuesta o un timeout de 5 s cuenta como fallo.
Reintentos: 1 min, 5 min, 30 min, 2 h y 12 h. Tras el sexto intento la entrega pasa a la cola de fallidos, desde donde RH o el equipo técnico pueden reenviarla. Rotación: al rotar el secreto, el anterior sigue firmando en paralelo durante 24 horas para que actualices tu sistema sin cortes.
Catálogo de eventos:
employee.created · employee.updated · employee.transferred · employee.terminated · employee.enabled_for_app · employee.disabled_for_app · attendance.clock_in · attendance.clock_out · attendance.break_started · attendance.break_ended · attendance.late_detected · attendance.absence_detected · attendance.overtime_detected · attendance.event_corrected · attendance.incident_created · attendance.incident_approved · attendance.incident_rejected · shift.assigned · shift.changed · device.connected · device.disconnected · device.sync_failed · compliance.rule_published · certification.expiring · certification.expired · training.completed · attendance.event.created · compliance.finding.created
7. Buenas prácticas
- Guarda el
client_secreten variables de entorno; nunca en el cliente ni en el repositorio. - Reintenta con el mismo
idempotency-key: Huminy no duplicará el evento. - Sincroniza el reloj de tu servidor (NTP): la firma expira a los 5 minutos.
- Los eventos son inmutables: una corrección se registra como ajuste con motivo, nunca borrando.
- Solicita únicamente los alcances que tu sistema necesita.
¿Necesitas un adaptador específico (QR, NFC, biométrico, WhatsApp) o mapeo de plantilla desde tu nómina? Escríbenos desde el panel de RH y lo configuramos contigo.