Registrar
Registra un lote de checadas y deriva los retardos de los días afectados.
Descripcion general
Este endpoint recibe un lote de checadas desde un reloj checador o una integración. Está pensado para que el dispositivo reenvíe lotes completos sin miedo: la ingesta es idempotente, una misma marca (mismo empleo, misma marca de tiempo) nunca se duplica.
El lote es todo o nada: si una sola fila es inválida o su empleado no se puede resolver, no se registra ninguna checada y la respuesta lista los problemas fila por fila.
Cuando el lote entra, la plataforma vuelve a evaluar los días que tocaste y deriva retardos, nunca faltas. Si la organización activó Derivar faltas y uno de esos días ya tenía una falta derivada por no tener checadas, la checada nueva la retira. La derivación solo corre si la organización tiene activado el interruptor Derivar retardos en Configuración → Reloj checador, y si el empleo tiene un horario efectivo (el de su contrato, o el horario default de la organización).
Requiere que la API key tenga el permiso Registrar checadas.
Endpoint
https://app.integranom.com/api/v1/time-clock-eventsRegistra un lote de checadas
Hasta 100 checadas por solicitud. El ejemplo sube la entrada y la salida de un empleado cuyo horario empieza a las 9:00 con 15 minutos de tolerancia: como llegó a las 9:20, se deriva un retardo → derived.created: 1.
created son las checadas nuevas; duplicates, las que ya existían (o venían repetidas en el mismo lote). Reenviar el lote completo devuelve created: 0 y no vuelve a derivar nada — la derivación anterior sigue en pie.
Campos del cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
events | object[] | Sí | 1–100 checadas. |
confirm_retro | boolean | No | Autoriza que los días dentro de un periodo cerrado se registren como ajuste retroactivo. Ver abajo. |
Campos de cada checada
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
employee_number | integer | Sí | Número del empleado dentro de la organización. |
timestamp | string (ISO 8601) | Sí | Instante de la marca, con zona horaria (...Z o ...-06:00). Una hora local sin offset se rechaza por ambigua. |
direction | "in" | "out" | No | Dirección declarada por el dispositivo. Una marca "out" nunca cuenta como la llegada del día. |
device_id | string | No | Identificador del dispositivo. Máximo 120 caracteres. |
Dias dentro de un periodo cerrado (ajuste retroactivo)
Cerrar un periodo es definitivo. Un retardo derivado de una checada con fecha dentro de sus días no reescribe la nómina ya pagada: se registra como un ajuste retroactivo que corrige la diferencia en el siguiente periodo.
Por eso, si el local_date de alguna checada cae en un periodo cerrado, el lote se rechaza con 409 RETRO_CONFIRMATION_REQUIRED (con retro_periods, los periodos afectados) y no se registra nada. Reenvíalo con confirm_retro: true para aceptar.
La puerta solo aplica cuando la derivación de retardos está activada: con el interruptor apagado una checada no deriva retardos y el lote entra sin confirmación. Con Derivar faltas encendida, una checada de un día que tenía una falta derivada la retira aunque el periodo esté cerrado; ese cambio entra solo como ajuste retroactivo, sin pedir confirm_retro.
Como se identifica al empleado
Cada checada debe traer employee_number: el número del empleado dentro de la organización. Con él se busca su empleo activo o pendiente, y ahí aterriza la checada.
Si el número no existe en la organización → EMPLOYEE_NOT_FOUND. Si existe pero la persona no tiene un empleo activo ni pendiente → NO_ACTIVE_EMPLOYMENT.
Cuando alguien tiene más de un empleo abierto en la misma organización, la checada aterriza en el más reciente.
Que se deriva (y que no)
| Situación | Resultado |
|---|---|
| Primera marca del día más tarde que la hora de entrada + tolerancia | Retardo en el registro de asistencia, con origen time_clock. |
| Día laborable sin checadas | Nada al recibir el lote. Con Derivar faltas encendida, un proceso nocturno lo registra como falta con origen time_clock cuando el día termina. |
| Día con una falta derivada que recibe su primera checada | La falta derivada se elimina. |
| Primera marca del día en o después de la hora de salida | Nada — se asume una salida sin registrar del día anterior. |
| El día ya tiene una incidencia capturada a mano | Nada. Lo manual siempre gana; el motor no pisa lo que RH ya registró. |
| Turno nocturno: llegada después de medianoche | Nada. Esa marca cae en el día natural siguiente y no se compara contra la entrada del turno. |
| El empleo no tiene horario efectivo | Nada. |
Forma de la respuesta
201 — el lote se registró.
| Campo | Significado |
|---|---|
summary.total | Checadas enviadas en la solicitud. |
summary.created | Checadas nuevas registradas. |
summary.duplicates | Checadas que ya existían o venían repetidas en el lote. |
derived.created | Retardos derivados nuevos en el registro de asistencia. |
derived.updated | Retardos derivados cuya cantidad cambió. |
derived.deleted | Retardos derivados que dejaron de aplicar y se retiraron. |
Errores
| Status | Código | Causa |
|---|---|---|
400 | — | Cuerpo mal formado, o events vacío o con más de 100 filas. |
400 | INVALID_INPUT | Alguna fila no pasó validación (timestamp sin zona horaria, direction fuera de in/out, etc.). No se registra nada. |
400 | EMPLOYEE_NOT_FOUND | El employee_number no existe en la organización. |
400 | NO_ACTIVE_EMPLOYMENT | El empleado no tiene empleo activo o pendiente. |
401 | — | API key ausente o inválida. |
403 | — | La API key no tiene el permiso Registrar checadas. |
409 | RETRO_CONFIRMATION_REQUIRED | Algún día cae en un periodo cerrado. Reenvía con confirm_retro: true. |
Los errores de fila llegan con el índice dentro de events y los datos de la checada, para que puedas identificarla:
{
"message": "Validation failed for 1 event(s). No events were ingested.",
"summary": { "total": 2, "with_errors": 1 },
"errors": [
{
"index": 1,
"event": {
"employee_number": 9999,
"timestamp": "2026-06-05T18:03:00-06:00"
},
"issues": [
{
"field": "employee_number",
"code": "EMPLOYEE_NOT_FOUND",
"message": "That 'employee_number' does not exist in this organization."
}
]
}
]
}
