API-konventioner
Regler som gäller alla resurser i v1.
| Område | Regel |
|---|---|
| Format | JSON UTF-8. Requests med body skickar Content-Type: application/json. |
| ID:n | Publika UUID:er. Interna numeriska ID:n exponeras aldrig. |
| Datum | ISO 8601. Tidpunkter i UTC (2026-07-08T09:30:00Z); kalenderdatum YYYY-MM-DD. |
| Base URL | Versionerad i pathen: https://api.kinmu.app/v1 · Dev: https://api.dev.kinmu.app/v1. |
Paginering (cursor)
Alla listor pagineras med cursor:
?limit=(default 25, max 100) ·?cursor=<opak>.- Svar:
{ "data": [...], "meta": { "next_cursor": "…"|null, "has_more": true|false } }. - För nästa sida skickar du tillbaka
cursor=<meta.next_cursor>.has_more=falseellernext_cursor=null→ slut.
curl "https://api.kinmu.app/v1/employees?limit=50&cursor=eyJpZCI6MTIzfQ" \
-H "Authorization: Bearer kinmu_sk_live_…"cursor är opak: bygg den inte och parsa den inte — skicka tillbaka den som den är.
Inkrementell synkronisering (updated_since)
Alla listor accepterar ?updated_since=<ISO 8601> för att hämta endast det som ändrats sedan den tidpunkten (inkrementell polling för BI och ERP-system).
curl "https://api.kinmu.app/v1/employees?updated_since=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer kinmu_sk_live_…"Spara tidpunkten för din senaste synkronisering och använd den som updated_since i nästa. Hela mönstret finns i BI-guiden.
Fel
Alla fel följer 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" }
}Programmera mot fältet code (stabilt), inte mot title/detail.
Kodtabell
code | HTTP | När |
|---|---|---|
unauthenticated | 401 | Nyckeln saknas, är ogiltig, återkallad eller utgången. |
invalid_scope | 403 | Nyckeln saknar det scope som krävs (errors.required_scope). |
subscription_inactive | 403 | Företagets prenumeration är pausad eller saknas. |
addon_disabled | 403 | Addonet Public API är inte aktivt för företaget. |
validation_failed | 422 | Ogiltig body eller ogiltiga parametrar (errors med detaljer per fält). |
not_found | 404 | Resursen finns inte eller tillhör ett annat företag. |
conflict | 409 | Tillståndskonflikt (t.ex. besluta en redan beslutad frånvaro). |
idempotency_conflict | 409 | Samma Idempotency-Key återanvändes med en annan body. |
rate_limited | 429 | Minutgränsen överskriden (se Retry-After). |
quota_exceeded | 429 | Månadskvoten förbrukad. |
billing_required | 402 | Planen tillåter inte åtgärden (t.ex. ny medarbetare utan ledig plats). |
internal_error | 500 | Internt fel. |
Multitenant-isolering. Att begära en resurs som tillhör ett annat företag ger 404 (not_found), aldrig en 403 som avslöjar att den finns.
Rate limits och kvot
Varje svar (2xx och 4xx) innehåller:
| Header | Betydelse |
|---|---|
X-RateLimit-Limit | Nyckelns gräns per minut. |
X-RateLimit-Remaining | Återstående requests i det aktuella fönstret. |
X-RateLimit-Reset | Unix-timestamp när fönstret nollställs. |
X-Kinmu-Quota-Remaining | Återstående requests av månadskvoten. |
Limits: live 120/min, test 30/min. Månadskvot: live 10.000 + 1.000×empleados_activos (max 100 000); test 5.000.
Överskrids minutgränsen → 429 rate_limited med Retry-After: <sekunder>. När kvoten är förbrukad → 429 quota_exceeded. Försök igen med backoff och respektera 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 respHåll koll på X-RateLimit-Remaining och X-Kinmu-Quota-Remaining och glesa ut dina requests innan du får en 429.
Idempotens
I muterande metoder (POST / PATCH / DELETE) kan du skicka Idempotency-Key: <unik>:
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" }'Den första requesten körs och dess svar cachas i 24 h; skickar du om den med samma body får du det ursprungliga svaret tillbaka (utan att den körs om). Att återanvända samma key med en annan body → 409 idempotency_conflict.
Skapandet av webhooks är det enda undantaget: dess copy-once-secret cachas aldrig.