Webhooks
Subscribe to events and have Kiket POST to your endpoint with signed payloads.
Webhooks are how Kiket tells your systems about things happening. Register a URL and a list of events; Kiket POSTs to it whenever those events fire.
Register a webhook
curl -X POST https://api.kiket.dev/api/v1/webhooks \
-H "Authorization: Bearer $KIKET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-service.example.com/kiket",
"events": ["case.created", "case.transitioned", "sla.breach"]
}'The signing secret is generated automatically and returned masked on subsequent GET requests. Copy it from the create response or from Settings → Webhooks when you need to verify signatures.
App → Settings → Webhooks → New webhook. Paste URL, pick events, save. Copy the signing secret somewhere safe — it is shown once at creation.
Event catalog
| Event | Fires when |
|---|---|
case.created | A new operational case is created |
case.updated | Any mutable field changes |
case.transitioned | Workflow state changes (includes from and to) |
case.assigned | Assignee changes |
case.commented | Comment added |
sla.warning | Warning threshold crossed |
sla.breach | Breach threshold crossed |
approval.requested | Approval chain starts |
approval.decided | Approver grants or denies |
workspace.updated | Workspace metadata changes |
These match the event picker in Settings → Webhooks and notification preferences.
Payload shape
{
"id": "evt_01HGZ...",
"type": "case.transitioned",
"createdAt": "2026-04-14T10:00:00Z",
"organizationId": "org_01HGZ...",
"workspaceId": "ws_01HGZ...",
"data": {
"case": {
"id": "case_01HGZ...",
"processId": "proc_01HGZ...",
"title": "Acme renewal",
"currentStateKey": "legal_review"
},
"from": "intake",
"to": "legal_review",
"actor": { "id": "usr_01HGZ...", "email": "pm@acme.com" }
}
}Exact fields vary by event type; always branch on type and treat unknown keys as forward-compatible.
Signing
Every request is signed:
X-Kiket-Signature: sha256=<hex>
X-Kiket-Timestamp: 1729700400The signature is HMAC-SHA256(secret, "<timestamp>.<body>"). Verify before trusting the payload.
import { verifyWebhook } from '@kiket/sdk/webhooks';
const ok = verifyWebhook(rawBody, headers['x-kiket-signature'], headers['x-kiket-timestamp'], WEBHOOK_SECRET);from kiket.webhooks import verify
ok = verify(raw_body, headers['X-Kiket-Signature'], headers['X-Kiket-Timestamp'], WEBHOOK_SECRET)ok := webhooks.Verify(rawBody, headers.Get("X-Kiket-Signature"), headers.Get("X-Kiket-Timestamp"), webhookSecret)Retries
- 5xx and timeouts retry with exponential backoff: 30s, 1m, 5m, 30m, 2h, 8h.
- After 6 attempts, the delivery is marked failed and shown in Settings → Webhooks → Deliveries.
- 4xx (except 429) don't retry — fix your endpoint and redeliver.
Redelivery
Every delivery has a unique ID. Redeliver from the UI or:
curl -X POST https://api.kiket.dev/api/v1/webhooks/deliveries/dlv_.../redeliver \
-H "Authorization: Bearer $KIKET_API_KEY"Debugging
- Settings → Webhooks → Deliveries shows recent attempts with request and response bodies.
- Use webhook.site or ngrok to inspect payloads in dev.
Best practices
- Return
2xxfast. If you need heavy work, queue it and return immediately. - Verify the signature on every call.
- Use the
idfield for idempotency — Kiket may redeliver the same event if your ack is late. - Subscribe to specific events, not wildcards, to avoid noise.
Inbound vs outbound
This page covers outbound webhooks (Kiket → your HTTPS endpoint). Evidence adapters use separate ingress URLs (POST /integrations/*/webhook) to send operational events into Kiket. See Integrations overview.