Kiket docs
API & SDKs

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

EventFires when
case.createdA new operational case is created
case.updatedAny mutable field changes
case.transitionedWorkflow state changes (includes from and to)
case.assignedAssignee changes
case.commentedComment added
sla.warningWarning threshold crossed
sla.breachBreach threshold crossed
approval.requestedApproval chain starts
approval.decidedApprover grants or denies
workspace.updatedWorkspace 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: 1729700400

The 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 2xx fast. If you need heavy work, queue it and return immediately.
  • Verify the signature on every call.
  • Use the id field 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.

On this page