Skip to Content
Gidsen per use caseBI / Power BI

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

ResourceLevert
work-summariesWerktijdmetrics klaar voor aggregatie (uren, overuren, nachturen).
check-insData op eventniveau voor analyse van aanwezigheid en stiptheid.
absencesVerzuim per type en periode.
vacation-balancesVerlofsaldi en -reserveringen.
locations / unitsDimensies 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 Table

Om 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.

Last updated on