Skip to Content
Guías por caso de usoControl de accesos

Control de accesos

Objetivo: que tu sistema de control de accesos (tornos, lectores de tarjeta, kioscos) registre fichajes en Kinmu en tiempo real.

Scopes necesarios: org:fichajes:write (registrar) y org:fichajes:read (consultar).

Registrar un fichaje

POST /v1/check-ins registra un evento en nombre de un empleado. Se persiste con source=api, queda auditado y respeta las validaciones de jornada (no hay bypass de reglas).

curl -s -X POST "$KINMU_BASE_URL/check-ins" \ -H "Authorization: Bearer $KINMU_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "employee_id": "a1b2c3d4-…", "type": "in", "timestamp": "2026-07-08T08:00:00Z", "location_id": "loc-uuid", "note": "Acceso puerta principal" }'

Campos del body:

CampoObligatorioNotas
employee_idUUID público del empleado.
typein, out, break_start o break_end.
timestampISO 8601 en UTC. Debe caer en la ventana [ahora − 24 h, ahora + 5 min]; fuera de ella → 422 validation_failed.
location_idNoCentro donde ocurre el fichaje.
noteNoTexto libre (p. ej. identificador del lector).

Respuesta 201:

{ "id": "ci-uuid", "employee_id": "a1b2c3d4-…", "type": "in", "timestamp": "2026-07-08T08:00:00Z", "location": { "id": "loc-uuid", "name": "Sede Madrid" }, "source": "api", "validated": true, "created_at": "2026-07-08T08:00:01Z", "updated_at": "2026-07-08T08:00:01Z" }

La ventana de timestamp es estrecha: 24 h hacia atrás y 5 minutos hacia delante. Un lector que acumule eventos sin red durante más de 24 h verá rechazado el lote al recuperar la conexión, evento por evento, con 422. Diseña el buffer para volcar en cuanto haya red, y trata ese 422 como un caso a conciliar a mano (o desde el panel), no como algo reintentable: el reintento tampoco entrará.

Usa Idempotency-Key en cada fichaje. Los tornos reintentan ante cortes de red; con una key idempotente evitas registrar el mismo acceso dos veces. Reenviar la misma key devuelve el fichaje original; reutilizarla con otro body da 409.

Mapear tus empleados

Tu sistema de accesos identifica personas por tarjeta o PIN; Kinmu por employee_id (UUID). Construye el mapeo una vez y refréscalo periódicamente:

Descarga los empleados y su estructura

curl -s "$KINMU_BASE_URL/employees?status=active&limit=100" \ -H "Authorization: Bearer $KINMU_API_KEY" curl -s "$KINMU_BASE_URL/locations" -H "Authorization: Bearer $KINMU_API_KEY"

Guarda el mapeo tarjeta → employee_id y zona → location_id

Usa email o un campo de tu maestro para casar personas; guarda los UUID de Kinmu. El email de empleado es único por empresa, no globalmente: la misma persona puede existir en otra empresa de Kinmu sin colisionar con la tuya.

Si tu integración da de alta empleados (POST /v1/employees), ten en cuenta que la respuesta puede ser 402 billing_required: la suscripción está viva pero el plan no tiene asientos libres. No es reintentable; hay que ampliar el plan en el panel.

Refresca con updated_since

Vuelve a leer solo lo que cambió: GET /v1/employees?updated_since=<última sync>.

Consultar fichajes

Para conciliar, lee los eventos con un rango obligatorio de ≤ 92 días:

curl -s "$KINMU_BASE_URL/check-ins?employee_id=a1b2…&from=2026-07-01&to=2026-07-08" \ -H "Authorization: Bearer $KINMU_API_KEY"

¿Quieres reaccionar en tiempo real a cada fichaje (por ejemplo, para un panel de presencia)? Suscríbete al evento checkin.created con webhooks en lugar de hacer polling.

Errores frecuentes

SituaciónRespuesta
Falta org:fichajes:write403 invalid_scope
timestamp fuera de la ventana (> 24 h en el pasado o > 5 min en el futuro) o type inválido422 validation_failed (con errors)
Reintento con misma Idempotency-Key y body distinto409 idempotency_conflict
Empleado de otra empresa404 not_found
Alta de empleado sin asiento libre en el plan402 billing_required
Last updated on