API-conventies
Regels die voor alle resources van v1 gelden.
| Onderwerp | Regel |
|---|---|
| Formaat | JSON UTF-8. Requests met een body sturen Content-Type: application/json mee. |
| IDs | Publieke UUID’s. Interne numerieke IDs worden nooit blootgesteld. |
| Datums | ISO 8601. Tijdstippen in UTC (2026-07-08T09:30:00Z); kalenderdatums als YYYY-MM-DD. |
| Base URL | Versie in het pad: https://api.kinmu.app/v1 · Dev: https://api.dev.kinmu.app/v1. |
Paginering (cursor)
Alle lijst-endpoints pagineren met een cursor:
?limit=(default 25, max 100) ·?cursor=<opaak>.- Response:
{ "data": [...], "meta": { "next_cursor": "…"|null, "has_more": true|false } }. - Stuur voor de volgende pagina
cursor=<meta.next_cursor>mee.has_more=falseofnext_cursor=null→ einde.
curl "https://api.kinmu.app/v1/employees?limit=50&cursor=eyJpZCI6MTIzfQ" \
-H "Authorization: Bearer kinmu_sk_live_…"De cursor is opaak: bouw of parse hem niet zelf, maar stuur hem ongewijzigd terug.
Incrementele synchronisatie (updated_since)
Alle lijst-endpoints accepteren ?updated_since=<ISO 8601> om alleen wat er sinds dat moment is gewijzigd op te halen (incrementeel pollen voor BI en ERP’s).
curl "https://api.kinmu.app/v1/employees?updated_since=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer kinmu_sk_live_…"Bewaar het tijdstip van je laatste synchronisatie en gebruik het als updated_since bij de volgende. Zie het volledige patroon in de BI-gids.
Fouten
Alle fouten volgen RFC 9457 (application/problem+json):
{
"type": "https://docs.kinmu.app/errors/invalid_scope",
"title": "Scope insuficiente",
"status": 403,
"code": "invalid_scope",
"detail": "La API key no tiene el scope requerido: org:empleados:read.",
"errors": { "required_scope": "org:empleados:read" }
}Programmeer tegen het veld code (stabiel), niet tegen title/detail.
Codetabel
code | HTTP | Wanneer |
|---|---|---|
unauthenticated | 401 | De key ontbreekt, is ongeldig, ingetrokken of verlopen. |
invalid_scope | 403 | De key mist de vereiste scope (errors.required_scope). |
subscription_inactive | 403 | Het abonnement van het bedrijf is opgeschort of ontbreekt. |
addon_disabled | 403 | De addon Public API is niet actief voor het bedrijf. |
validation_failed | 422 | Ongeldige body/parameters (errors met details per veld). |
not_found | 404 | De resource bestaat niet of hoort bij een ander bedrijf. |
conflict | 409 | Statusconflict (bijv. beslissen over een al besliste afwezigheid). |
idempotency_conflict | 409 | De Idempotency-Key is hergebruikt met een andere body. |
rate_limited | 429 | Limiet per minuut overschreden (zie Retry-After). |
quota_exceeded | 429 | Maandelijkse quota opgebruikt. |
billing_required | 402 | Het plan staat de actie niet toe (bijv. medewerker aanmaken zonder seat). |
internal_error | 500 | Interne fout. |
Multitenant-isolatie. Een resource van een ander bedrijf opvragen geeft 404 (not_found), nooit een 403 die het bestaan ervan verraadt.
Rate limits en quota
Elke response (2xx en 4xx) bevat:
| Header | Betekenis |
|---|---|
X-RateLimit-Limit | Limiet per minuut van de key. |
X-RateLimit-Remaining | Resterende requests in het huidige venster. |
X-RateLimit-Reset | Unix-timestamp waarop het venster reset. |
X-Kinmu-Quota-Remaining | Resterende requests van de maandelijkse quota. |
Limieten: live 120/min, test 30/min. Maandelijkse quota: live 10.000 + 1.000×actieve_medewerkers (max 100.000); test 5.000.
Overschrijd je de minuutlimiet → 429 rate_limited met Retry-After: <seconden>. Is de quota op → 429 quota_exceeded. Retry met backoff en respecteer Retry-After.
import time, requests
def call_with_retry(session, method, url, **kwargs):
for attempt in range(5):
resp = session.request(method, url, **kwargs)
if resp.status_code != 429:
return resp
wait = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
resp.raise_for_status()
return respHoud X-RateLimit-Remaining en X-Kinmu-Quota-Remaining in de gaten en spreid je requests voordat je een 429 krijgt.
Idempotentie
Bij muterende methodes (POST / PATCH / DELETE) kun je Idempotency-Key: <uniek> meesturen:
curl -s -X POST "https://api.kinmu.app/v1/check-ins" \
-H "Authorization: Bearer kinmu_sk_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f9a…-uuid" \
-d '{ "employee_id": "…", "type": "in", "timestamp": "2026-07-08T08:00:00Z" }'De eerste request wordt uitgevoerd en de response wordt 24 uur gecachet; een herhaalde request met dezelfde body krijgt de oorspronkelijke response terug (zonder opnieuw uit te voeren). Dezelfde key hergebruiken met een andere body → 409 idempotency_conflict.
Het aanmaken van een webhook is de enige uitzondering: het copy-once secret wordt nooit gecachet.