Skip to Content
Use-case guidesBI / Power BI

BI / Power BI

Goal: bring time tracking data into your data warehouse or directly into Power BI / Looker / Metabase through incremental sync.

Recommended scopes (read-only): org:fichajes:read, org:ausencias:read, org:saldos:read, org:estructura:read.

For BI use a dedicated read-only key. That way you can revoke or rotate it without affecting write integrations.

Pattern: incremental polling with updated_since

All listings accept updated_since=<ISO8601> and return only what has changed since that instant. The pattern:

Initial load (backfill)

Walk each resource paginating by cursor until has_more=false. Store the start instant as a watermark (watermark).

Incremental loads

On each scheduled run, request ?updated_since=<watermark> and update your watermark to the instant just before the call started.

Deduplicate by id

Since updated_since is based on updated_at, the same record may reappear if it changed. Do an upsert by id (UUID) in your store.

Python example

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 # Watermark BEFORE calling, so you don't miss records written during the 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)

Take the watermark before starting the sync, not after. That way the records written while the process was running are picked up in the next pass.

Useful resources for BI

ResourceProvides
work-summariesWorkday metrics ready for aggregation (hours, overtime, night).
check-insEvent-level grain for presence and punctuality analysis.
absencesAbsenteeism by type and period.
vacation-balancesVacation balances and provisions.
locations / unitsDimensions to segment by (site, department).

Connecting from Power BI

Power BI can consume the API directly with Web.Contents and an authorization header. Simplified example in Power Query (M):

let BaseUrl = "https://api.kinmu.app/v1", ApiKey = "kinmu_sk_live_…", // use Parameters / credential store, don't write it in plaintext 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

To paginate in Power Query, wrap the call in a function that follows meta.next_cursor with List.Generate until has_more is false.

Respect the rate limits: for large volumes, schedule the refresh outside peak hours and watch X-Kinmu-Quota-Remaining.

Event-driven alternative

If you prefer not to poll, subscribe to webhooks (checkin.created, absence.approved, vacation_balance.updated, …) and update your store as each event arrives. They combine well: webhooks for real time + a nightly poll with updated_since as a safety net.

Last updated on