Skip to content

Webhooks

Webhooks deliver real-time events to your services whenever workflows, boards, or analytics change.

Subscription Methods

  • Project-level – Configure under Project → Integrations → Webhooks.
  • Organization-level – Apply to all projects within an organization.
  • Extensions – Automatically subscribe via manifests.

Event Types

  • issue.created
  • issue.updated
  • issue.transitioned
  • workflow.synced
  • board.generated
  • analytics.metric_alert
  • extension.installation

Payload Structure

{
  "id": "evt_01HXX...",
  "event": "issue.transitioned",
  "occurred_at": "2025-04-05T12:34:56Z",
  "project": {
    "slug": "core-platform",
    "name": "Core Platform"
  },
  "data": {
    "issue": { "key": "CORE-42", "title": "Fix bug" },
    "transition": { "from": "review", "to": "done", "performed_by": "alex@example.com" }
  }
}

issue.created

{
  "event": "issue.created",
  "timestamp": "2026-04-01T12:00:00Z",
  "organization_id": 42,
  "issue_id": 456,
  "project_id": 10,
  "title": "GDPR Access Request - Jan Novak",
  "status": "received",
  "issue_type": "dsar",
  "priority": "high",
  "assignee_id": null,
  "custom_fields": {
    "requester_name": "Jan Novak",
    "requester_email": "jan@example.com",
    "request_type": "access"
  },
  "labels": []
}

issue.status_changed

{
  "event": "issue.status_changed",
  "timestamp": "2026-04-01T14:30:00Z",
  "organization_id": 42,
  "issue_id": 456,
  "project_id": 10,
  "title": "GDPR Access Request - Jan Novak",
  "status": "verification",
  "previous_status": "received",
  "issue_type": "dsar",
  "priority": "high",
  "assignee_id": 7
}

comment.created

{
  "event": "comment.created",
  "timestamp": "2026-04-01T15:00:00Z",
  "organization_id": 42,
  "comment_id": 789,
  "issue_id": 456,
  "project_id": 10,
  "author": {
    "id": 7,
    "name": "Eva Dvorakova",
    "email": "eva@acme.cz"
  },
  "body": "Identity verification document received and validated."
}

Delivery & Retries

  • Requests include X-Kiket-Event, X-Kiket-Signature (HMAC SHA-256), and X-Kiket-Delivery headers.
  • Respond with 2xx within 10 seconds. Failures retry up to 9 times with exponential backoff.
  • Use the delivery log in the UI to replay events manually.

Security

  • Verify signatures using the shared secret shown in the webhook configuration.
  • Restrict receiver endpoints to known IP ranges if necessary.
  • Rotate secrets regularly; Kiket keeps previous secrets active for 24 hours to avoid downtime.

Testing

  • Use the “Send Test Event” button in the UI to validate endpoints.
  • CLI: kiket webhooks send --event issue.created --url https://localhost:3000/webhook.

Webhooks keep your external systems in sync with Kiket’s workflow engine.

Webhook Subscriptions API

For standalone products and external integrations — subscribe to events programmatically.

Create a subscription

curl -X POST https://kiket.dev/api/v1/webhook_subscriptions \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d {
    "webhook_subscription": {
      "url": "https://myapp.com/webhooks",
      "events": ["issue.created", "issue.status_changed"],
      "description": "My app webhook"
    }
  }

The response includes a secret (shown only on create and show) for verifying signatures.

Available events

issue.created, issue.updated, issue.deleted, issue.assigned, issue.status_changed, issue.priority_changed, comment.created, comment.updated, project.created, project.updated, workflow.state_changed, workflow.action_triggered, milestone.created, milestone.reached, user.joined, user.role_changed

Use ["*"] to subscribe to all events.

Verify signatures

Each delivery includes:

Header Value
X-Kiket-Event Event type (e.g., issue.created)
X-Kiket-Signature sha256=<HMAC-SHA256 hex digest>
X-Kiket-Delivery Unique delivery ID

Verify using your subscription’s secret:

expected = "sha256=" + OpenSSL::HMAC.hexdigest("SHA256", secret, request.body.read)
actual = request.headers["X-Kiket-Signature"]
Rack::Utils.secure_compare(expected, actual)

Manage subscriptions

GET    /api/v1/webhook_subscriptions          # list all
GET    /api/v1/webhook_subscriptions/:id      # show (includes secret)
PATCH  /api/v1/webhook_subscriptions/:id      # update (url, events, status)
DELETE /api/v1/webhook_subscriptions/:id      # delete

Set status: "paused" to temporarily disable a subscription without deleting it. Subscriptions are auto-disabled after 10 consecutive delivery failures.