BI / Power BI
Doel: de tijdregistratiedata naar je datawarehouse brengen, of direct naar Power BI / Looker / Metabase, via incrementele synchronisatie.
Aanbevolen scopes (alleen-lezen): org:fichajes:read, org:ausencias:read, org:saldos:read, org:estructura:read.
Gebruik voor BI een aparte alleen-lezen key. Dan kun je die intrekken of roteren zonder schrijvende integraties te raken.
Patroon: incrementeel pollen met updated_since
Alle lijst-endpoints accepteren updated_since=<ISO8601> en retourneren alleen wat er sinds dat moment is gewijzigd. Het patroon:
Initiële load (backfill)
Loop elke resource door en pagineer met cursor tot has_more=false. Bewaar het starttijdstip als watermark (watermark).
Incrementele loads
Vraag bij elke geplande run ?updated_since=<watermark> op en zet je watermark op het tijdstip vóór de start van de call.
Dedupliceer op id
Omdat updated_since op updated_at is gebaseerd, kan hetzelfde record opnieuw verschijnen als het is gewijzigd. Doe een upsert op id (UUID) in je opslag.
Voorbeeld in Python
import os, requests
from datetime import datetime, timezone
BASE = os.environ["KINMU_BASE_URL"]
KEY = os.environ["KINMU_API_KEY"]
session = requests.Session()
session.headers.update({"Authorization": f"Bearer {KEY}"})
def sync(resource, since=None):
rows, cursor = [], None
params = {"limit": 100}
if since:
params["updated_since"] = since
while True:
if cursor:
params["cursor"] = cursor
r = session.get(f"{BASE}/{resource}", params=params, timeout=30)
r.raise_for_status()
body = r.json()
rows.extend(body["data"])
if not body["meta"]["has_more"]:
break
cursor = body["meta"]["next_cursor"]
return rows
# Marca de agua ANTES de llamar, para no perder registros escritos durante la sync
watermark = datetime.now(timezone.utc).isoformat()
employees = sync("employees", since=load_last_watermark()) # incremental
checkins = sync("check-ins", since=load_last_watermark())
save_watermark(watermark)Neem de watermark voordat je de synchronisatie start, niet erna. Zo komen records die tijdens de run zijn geschreven in de volgende run mee.
Nuttige resources voor BI
| Resource | Levert |
|---|---|
work-summaries | Werktijdmetrics klaar voor aggregatie (uren, overuren, nachturen). |
check-ins | Data op eventniveau voor analyse van aanwezigheid en stiptheid. |
absences | Verzuim per type en periode. |
vacation-balances | Verlofsaldi en -reserveringen. |
locations / units | Dimensies om op te segmenteren (locatie, afdeling). |
Verbinden vanuit Power BI
Power BI kan de API direct aanspreken met Web.Contents en een autorisatieheader. Vereenvoudigd voorbeeld in Power Query (M):
let
BaseUrl = "https://api.kinmu.app/v1",
ApiKey = "kinmu_sk_live_…", // usa Parámetros / almacén de credenciales, no lo escribas en claro
Source = Json.Document(
Web.Contents(BaseUrl, [
RelativePath = "work-summaries",
Query = [ period = "month", from = "2026-01-01", #"to" = "2026-12-31", limit = "100" ],
Headers = [ Authorization = "Bearer " & ApiKey, Accept = "application/json" ]
])
),
Data = Source[data],
Table = Table.FromRecords(Data)
in
TableOm in Power Query te pagineren, wikkel je de call in een functie die meta.next_cursor volgt met List.Generate tot has_more false is.
Respecteer de rate limits: plan de refresh voor grote volumes buiten piekuren en houd X-Kinmu-Quota-Remaining in de gaten.
Event-driven alternatief
Wil je liever niet pollen, abonneer je dan op webhooks (checkin.created, absence.approved, vacation_balance.updated, …) en werk je opslag bij zodra elk event binnenkomt. De combinatie werkt goed: webhooks voor realtime + een nachtelijke polling-run met updated_since als vangnet.