Skip to Content
Konventionen

API-Konventionen

Regeln, die für alle Ressourcen von v1 gelten.

ThemaRegel
FormatJSON UTF-8. Requests mit Body tragen Content-Type: application/json.
IDsÖffentliche UUIDs. Interne numerische IDs werden nie exponiert.
DatumsangabenISO 8601. Zeitpunkte in UTC (2026-07-08T09:30:00Z); Kalenderdaten als YYYY-MM-DD.
Base URLVersioniert im Pfad: https://api.kinmu.app/v1 · Dev: https://api.dev.kinmu.app/v1.

Paginierung (Cursor)

Alle Listen paginieren per Cursor:

  • ?limit= (Default 25, max. 100) · ?cursor=<opaco>.
  • Antwort: { "data": [...], "meta": { "next_cursor": "…"|null, "has_more": true|false } }.
  • Für die nächste Seite sendest du cursor=<meta.next_cursor>. has_more=false oder next_cursor=null → Ende.
curl "https://api.kinmu.app/v1/employees?limit=50&cursor=eyJpZCI6MTIzfQ" \ -H "Authorization: Bearer kinmu_sk_live_…"

Der cursor ist opak: Baue ihn nicht selbst zusammen und parse ihn nicht — sende ihn unverändert zurück.

Inkrementelle Synchronisierung (updated_since)

Alle Listen akzeptieren ?updated_since=<ISO 8601>, um nur die Änderungen seit diesem Zeitpunkt zu laden (inkrementelles Polling für BI und ERPs).

curl "https://api.kinmu.app/v1/employees?updated_since=2026-07-01T00:00:00Z" \ -H "Authorization: Bearer kinmu_sk_live_…"

Speichere den Zeitpunkt deiner letzten Synchronisierung und verwende ihn beim nächsten Lauf als updated_since. Das vollständige Pattern findest du im BI-Guide.

Fehler

Alle Fehler folgen 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" } }

Programmiere gegen das Feld code (stabil), nicht gegen title/detail.

Fehlercodes

codeHTTPWann
unauthenticated401Key fehlt, ist ungültig, widerrufen oder abgelaufen.
invalid_scope403Der Key hat den erforderlichen Scope nicht (errors.required_scope).
subscription_inactive403Das Abonnement des Unternehmens ist ausgesetzt oder fehlt.
addon_disabled403Das Addon Public API ist für das Unternehmen nicht aktiv.
validation_failed422Ungültiger Body/Parameter (errors mit Details pro Feld).
not_found404Die Ressource existiert nicht oder gehört einem anderen Unternehmen.
conflict409Zustandskonflikt (z. B. eine bereits entschiedene Abwesenheit erneut entscheiden).
idempotency_conflict409Die Idempotency-Key wurde mit einem anderen Body wiederverwendet.
rate_limited429Minutenlimit überschritten (siehe Retry-After).
quota_exceeded429Monatskontingent aufgebraucht.
billing_required402Der Plan erlaubt die Aktion nicht (z. B. Mitarbeitenden anlegen ohne freien Seat).
internal_error500Interner Fehler.

Multitenant-Isolation. Eine Ressource eines anderen Unternehmens anzufragen liefert 404 (not_found) — nie ein 403, das ihre Existenz verraten würde.

Rate Limits und Kontingent

Jede Antwort (2xx und 4xx) enthält:

HeaderBedeutung
X-RateLimit-LimitMinutenlimit des Keys.
X-RateLimit-RemainingVerbleibende Requests im aktuellen Fenster.
X-RateLimit-ResetUnix-Timestamp, zu dem das Fenster zurückgesetzt wird.
X-Kinmu-Quota-RemainingVerbleibende Requests des Monatskontingents.

Limits: live 120/min, test 30/min. Monatskontingent: live 10.000 + 1.000×empleados_activos (max. 100.000); test 5.000.

Beim Überschreiten des Minutenlimits → 429 rate_limited mit Retry-After: <segundos>. Bei aufgebrauchtem Kontingent → 429 quota_exceeded. Wiederhole mit Backoff und respektiere 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 resp

Behalte X-RateLimit-Remaining und X-Kinmu-Quota-Remaining im Blick, um deine Requests zu verteilen, bevor du ein 429 bekommst.

Idempotenz

Bei mutierenden Methoden (POST / PATCH / DELETE) kannst du Idempotency-Key: <único> senden:

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" }'

Der erste Request wird ausgeführt und seine Antwort 24 h gecacht; ein erneutes Senden mit dem gleichen Body liefert die ursprüngliche Antwort (ohne erneute Ausführung). Denselben Key mit einem anderen Body wiederverwenden → 409 idempotency_conflict.

Das Anlegen eines Webhooks ist die einzige Ausnahme: Sein copy-once-Secret wird nie gecacht.

Last updated on