Skip to Content
Webhooks

Webhooks

Statt zu pollen, abonniere ausgehende Events: Kinmu sendet einen POST an deinen HTTPS-Endpoint, sobald etwas Relevantes passiert. Jede Zustellung ist nach der Konvention Standard Webhooks  signiertverifiziere die Signatur immer, bevor du das Event verarbeitest.

Die Verwaltung von Endpoints erfordert den Scope webhooks:manage und erfolgt über das Dashboard oder die Endpoints unter /v1/webhook-endpoints.

Endpoint registrieren

Lege einen Endpoint an, mit deiner URL (HTTPS) und den Events, die dich interessieren:

curl -s -X POST "https://api.kinmu.app/v1/webhook-endpoints" \ -H "Authorization: Bearer kinmu_sk_live_…" \ -H "Content-Type: application/json" \ -d '{ "url": "https://tu-app.example.com/webhooks/kinmu", "events": ["absence.approved", "checkin.created"], "description": "Sync con nuestro ERP" }'

Die Antwort enthält das Signing-Secret (whsec_…), nur ein einziges Mal sichtbar. Bewahre es auf: Du brauchst es zum Verifizieren der Signaturen.

Verfügbare Verwaltung: GET (Liste), GET /{id}, PATCH /{id} (Events/Status), DELETE /{id}, POST /{id}/test (sendet ein ping), GET /{id}/deliveries (letzte Zustellungen) und POST /{id}/deliveries/{deliveryId}/retry (stellt eine bestimmte Zustellung neu ein). Maximal 5 aktive Endpoints pro Unternehmen.

Events

employee.created, employee.updated, employee.terminated, checkin.created, absence.requested, absence.approved, absence.denied, absence.cancelled, vacation_balance.updated, report.completed, ping.

Event-Payload

{ "id": "evt_…", "type": "absence.approved", "created_at": "…", "company_id": "…", "data": { } }

data enthält öffentliche IDs + Status (minimal); lade die vollständige Ressource per GET nach, wenn du alle Felder brauchst.

Signatur verifizieren

Jede Zustellung kommt mit drei Headern:

HeaderInhalt
webhook-idEindeutige ID des Events (Idempotenz in deinem Receiver).
webhook-timestampUnix-Timestamp des Versands.
webhook-signaturev1,<firma> (es können mehrere sein, durch Leerzeichen getrennt).

Algorithmus: firma = base64( HMAC_SHA256( key, "{webhook-id}.{webhook-timestamp}.{body_crudo}" ) ), mit dem Präfix v1,. Der Key ist der Teil nach whsec_ des Secrets (nur einmal beim Anlegen des Webhooks angezeigt), von Base64 zu Bytes dekodiert. Signiert wird der rohe Body (exakt empfangene Bytes), nicht das re-serialisierte JSON.

Verifizierung (lehne ab, wenn die Signatur nicht übereinstimmt oder webhook-timestamp mehr als 5 Min. von deiner Uhr abweicht):

const crypto = require('crypto'); function verify(secret, headers, rawBody) { const id = headers['webhook-id']; const ts = headers['webhook-timestamp']; if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // ±5 min const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64'); const expected = 'v1,' + crypto .createHmac('sha256', key) .update(`${id}.${ts}.${rawBody}`) .digest('base64'); return headers['webhook-signature'] .split(' ') .some(sig => crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))); }

Verifiziere und signiere über den rohen Body (exakt empfangene Bytes), nicht über das re-serialisierte JSON — jede Umformatierung macht die Signatur ungültig. Verwende die webhook-id als Idempotenzschlüssel in deinem Receiver, um erneute Zustellungen zu verwerfen.

Retries

Bei Fehlern (oder einer Antwort ≠ 2xx) wiederholt Kinmu mit Backoff: 1 min, 5 min, 30 min, 2 h, 12 h, 24 h. Antworte schnell mit 2xx; verarbeite asynchron, wenn du länger brauchst. Ein Endpoint, der 7 Tage in Folge fehlschlägt, wird automatisch deaktiviert.

Eine fehlgeschlagene Zustellung kannst du manuell neu einstellen mit POST /v1/webhook-endpoints/{id}/deliveries/{deliveryId}/retry (verwende die id der Zustellung aus GET /{id}/deliveries).

Best Practices

Antworte schnell, verarbeite im Hintergrund

Verifiziere die Signatur, stelle die Arbeit in eine Queue und antworte sofort mit 2xx.

Verifiziere immer die Signatur

Verarbeite keinen Payload, ohne webhook-signature geprüft zu haben. Behandle das Secret wie ein Credential.

Sei idempotent

Dedupliziere über die webhook-id. Retries sind normal.

Teste mit ping

Nutze POST /v1/webhook-endpoints/{id}/test, um ein ping-Event zu erhalten und deine Integration Ende-zu-Ende zu validieren.

Last updated on