Webhooks
Register HTTP endpoints to receive real-time notifications when boards, cards, columns, or attachments change. Webhooks fire from all interfaces — web UI, CLI, REST API, MCP server, and SDK — ensuring consistent delivery regardless of how a mutation is triggered.
- 20+ event types covering boards, cards, columns, comments, attachments, and forms
- HMAC-SHA256 signature verification with optional per-webhook secrets
- Manage via CLI (
kl webhooks add), REST API, SDK, or MCP tools - Powered by the external
kl-webhooks-pluginpackage - Registrations stored in
.kanban.jsonand persist across restarts
kl webhooks add \
--url https://example.com/hook \
--events task.created,task.moved \
--secret mykey
Webhooks
Kanban Lite fires webhooks on every mutation — task, comment, column, attachment, settings, and board changes. Webhooks are delivered via HTTP POST to any registered endpoint.
Overview
- Webhooks fire from all interfaces: REST API, CLI, MCP server, and the UI (via the standalone server).
- Events are emitted by the SDK event bus and delivered by the resolved
webhook.deliveryprovider, ensuring consistent behavior regardless of entry point. - The default runtime provider id is
webhooks, which resolves to the externalkl-webhooks-pluginpackage. kl-webhooks-pluginowns runtime delivery plus the standalone/api/webhooksroutes,kl webhooksCLI commands, and webhook MCP tools where those plugin seams are available.- Advanced SDK consumers can use
sdk.getExtension('kl-webhooks-plugin'); the direct webhook SDK methods remain stable compatibility shims. - MCP uses the same active-package discovery model as CLI and standalone.
kl-webhooks-pluginregisters the public webhook tools via the narrowmcpPluginseam. - Webhook registrations are stored in
.kanban.jsonand persist across server restarts. - Delivery is asynchronous and fire-and-forget (10-second timeout, failures are logged but do not block).
- Existing workspaces keep the same
.kanban.jsonwebhooksarray; no migration is required. - A workspace that only configures
webhookPluginstill activates webhook package discovery for provider, standalone, CLI, and MCP surfaces. - This file is generated from source metadata; do not edit
docs/webhooks.mdby hand.
Install and linking
Install kl-webhooks-plugin in the same environment that loads Kanban Lite:
npm install kl-webhooks-plugin
For local development, a sibling checkout at ../kl-webhooks-plugin is resolved automatically. npm link ../kl-webhooks-plugin is optional when you want an explicit local package link.
Configuration
Webhook delivery keeps its own top-level webhookPlugin config key. That key is also enough to activate plugin discovery for the webhook package's standalone routes, CLI commands, and MCP tools; the persisted registrations themselves stay in the existing top-level .kanban.json webhooks array:
{
"webhookPlugin": {
"webhook.delivery": {
"provider": "webhooks"
}
}
}
Registered webhooks are stored in your project's .kanban.json file:
{
"webhooks": [
{
"id": "wh_a1b2c3d4e5f67890",
"url": "https://example.com/webhook",
"events": ["task.created", "task.moved"],
"secret": "my-signing-key",
"active": true
}
]
}
Managing Webhooks
SDK
Webhook CRUD still converges on the same KanbanSDK methods: listWebhooks(), createWebhook(), updateWebhook(), deleteWebhook(), and getWebhookStatus().
For plugin-aware consumers, kl-webhooks-plugin also contributes an additive SDK extension bag available through sdk.getExtension('kl-webhooks-plugin'). Those extension methods and the direct SDK methods share the same backing store; the direct methods remain the compatibility path for existing callers.
REST API
These routes are plugin-owned when kl-webhooks-plugin is loaded by the standalone host.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/webhooks |
List all webhooks |
POST |
/api/webhooks |
Register a new webhook |
PUT |
/api/webhooks/:id |
Update a webhook |
DELETE |
/api/webhooks/:id |
Delete a webhook |
CLI
These commands are plugin-owned when kl-webhooks-plugin is loaded by the CLI host.
# List webhooks
kl webhooks
# Register a webhook
kl webhooks add --url https://example.com/hook --events task.created,task.moved
# Update a webhook
kl webhooks update <id> --active false
kl webhooks update <id> --events task.created,task.deleted --url https://new-url.com
# Delete a webhook
kl webhooks remove <id>
MCP Server
These tools are plugin-owned when kl-webhooks-plugin is loaded by the MCP host through the narrow mcpPlugin.registerTools(...) seam. Public tool names, schemas, auth wrapping, and secret redaction behavior remain unchanged: list_webhooks, add_webhook, update_webhook, remove_webhook
Payload Format
Every webhook delivery sends a JSON POST request with the following structure:
{
"event": "task.created",
"timestamp": "2026-02-24T12:00:00.000Z",
"data": { ... }
}
Headers:
| Header | Description |
|---|---|
Content-Type |
application/json |
X-Webhook-Event |
The event type (e.g., task.created) |
X-Webhook-Signature |
HMAC-SHA256 signature (only if a secret is configured) |
Signature Verification
If you provide a secret when registering a webhook, every delivery includes an X-Webhook-Signature header with the format sha256=<hex-digest>.
To verify:
const crypto = require('crypto')
function verifySignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
}
Delivery Behavior
- Webhooks are delivered asynchronously — the SDK operation completes without waiting for delivery.
- Each delivery has a 10-second timeout.
- Failed deliveries are logged to stderr but do not retry.
- Only HTTP
2xxresponses are considered successful. - Inactive webhooks (
active: false) are skipped. - Subscribing to
["*"]matches all events.
Event Reference
| Event | Category | Description |
|---|---|---|
task.created |
Task | A new task was created. |
form.submit |
Task | A card form payload was validated, persisted, and submitted. |
task.updated |
Task | A task was updated (fields changed, not moved). |
task.moved |
Task | A task was moved to a different column or transferred between boards. |
task.deleted |
Task | A task was permanently deleted. |
comment.created |
Comment | A comment was added to a task. |
comment.updated |
Comment | A comment was edited. |
comment.deleted |
Comment | A comment was removed from a task. |
column.created |
Column | A new column was added to a board. |
column.updated |
Column | A column was renamed or its color changed. |
column.deleted |
Column | A column was removed from a board. |
attachment.added |
Attachment | A file was attached to a task. |
attachment.removed |
Attachment | A file was removed from a task. |
settings.updated |
Settings | Board display settings were changed. |
board.created |
Board | A new board was created. |
board.updated |
Board | A board configuration was changed. |
board.deleted |
Board | A board was deleted. |
Task Events
task.created
A new task was created.
Trigger: Creating a task via API, CLI, MCP, or the UI.
Example payload:
{
"event": "task.created",
"timestamp": "2026-02-24T12:00:00.000Z",
"data": {
"id": "fix-login-bug-2026-02-24",
"status": "backlog",
"priority": "critical",
"assignee": "alice",
"labels": ["bug", "auth"],
"dueDate": null,
"comments": [],
"attachments": [],
"created": "2026-02-24T12:00:00.000Z",
"modified": "2026-02-24T12:00:00.000Z"
}
}
form.submit
A card form payload was validated, persisted, and submitted.
Trigger: Submitting an attached card form via the SDK, REST API, CLI, MCP, or the webview form tab.
Example payload:
{
"event": "form.submit",
"timestamp": "2026-03-19T12:10:00.000Z",
"data": {
"boardId": "default",
"card": {
"id": "investigate-outage-2026-03-19",
"status": "todo",
"priority": "high",
"formData": {
"incident-report": {
"severity": "critical",
"owner": "alice",
"service": "billing"
}
}
},
"form": {
"id": "incident-report",
"label": "incident-report",
"fromConfig": true
},
"data": {
"severity": "critical",
"owner": "alice",
"service": "billing"
}
}
}
task.updated
A task was updated (fields changed, not moved).
Trigger: Updating task content, priority, assignee, labels, or due date.
Example payload:
{
"event": "task.updated",
"timestamp": "2026-02-24T12:05:00.000Z",
"data": {
"id": "fix-login-bug-2026-02-24",
"status": "backlog",
"priority": "high",
"assignee": "bob",
"labels": ["bug"],
"dueDate": "2026-03-01",
"comments": [],
"attachments": [],
"created": "2026-02-24T12:00:00.000Z",
"modified": "2026-02-24T12:05:00.000Z"
}
}
task.moved
A task was moved to a different column or transferred between boards.
Trigger: Moving a task to a new status, or transferring it to another board.
Example payload:
{
"event": "task.moved",
"timestamp": "2026-02-24T12:10:00.000Z",
"data": {
"id": "fix-login-bug-2026-02-24",
"status": "in-progress",
"previousStatus": "backlog",
"priority": "high",
"assignee": "bob",
"modified": "2026-02-24T12:10:00.000Z"
}
}
task.deleted
A task was permanently deleted.
Trigger: Deleting a task via API, CLI, MCP, or the UI.
Example payload:
{
"event": "task.deleted",
"timestamp": "2026-02-24T12:15:00.000Z",
"data": {
"id": "fix-login-bug-2026-02-24",
"status": "in-progress",
"priority": "high"
}
}
Comment Events
comment.created
A comment was added to a task.
Trigger: Adding a comment to any task.
Example payload:
{
"event": "comment.created",
"timestamp": "2026-02-24T12:20:00.000Z",
"data": {
"id": 1,
"author": "alice",
"content": "Looks good, needs tests",
"date": "2026-02-24T12:20:00.000Z",
"cardId": "fix-login-bug-2026-02-24"
}
}
comment.updated
A comment was edited.
Trigger: Updating the content of an existing comment.
Example payload:
{
"event": "comment.updated",
"timestamp": "2026-02-24T12:25:00.000Z",
"data": {
"id": 1,
"author": "alice",
"content": "Updated: Looks great, tests added",
"date": "2026-02-24T12:20:00.000Z",
"cardId": "fix-login-bug-2026-02-24"
}
}
comment.deleted
A comment was removed from a task.
Trigger: Deleting a comment from any task.
Example payload:
{
"event": "comment.deleted",
"timestamp": "2026-02-24T12:30:00.000Z",
"data": {
"id": 1,
"author": "alice",
"content": "Updated: Looks great, tests added",
"date": "2026-02-24T12:20:00.000Z",
"cardId": "fix-login-bug-2026-02-24"
}
}
Column Events
column.created
A new column was added to a board.
Trigger: Adding a column via API, CLI, MCP, or settings.
Example payload:
{
"event": "column.created",
"timestamp": "2026-02-24T13:00:00.000Z",
"data": {
"id": "testing",
"name": "Testing",
"color": "#ff9900"
}
}
column.updated
A column was renamed or its color changed.
Trigger: Updating column name or color.
Example payload:
{
"event": "column.updated",
"timestamp": "2026-02-24T13:05:00.000Z",
"data": {
"id": "testing",
"name": "QA Testing",
"color": "#ff9900"
}
}
column.deleted
A column was removed from a board.
Trigger: Deleting an empty column.
Example payload:
{
"event": "column.deleted",
"timestamp": "2026-02-24T13:10:00.000Z",
"data": {
"id": "testing",
"name": "QA Testing",
"color": "#ff9900"
}
}
Attachment Events
attachment.added
A file was attached to a task.
Trigger: Uploading or adding an attachment to any task.
Example payload:
{
"event": "attachment.added",
"timestamp": "2026-02-24T13:15:00.000Z",
"data": {
"cardId": "fix-login-bug-2026-02-24",
"attachment": "screenshot.png"
}
}
attachment.removed
A file was removed from a task.
Trigger: Deleting an attachment from any task.
Example payload:
{
"event": "attachment.removed",
"timestamp": "2026-02-24T13:20:00.000Z",
"data": {
"cardId": "fix-login-bug-2026-02-24",
"attachment": "screenshot.png"
}
}
Settings Events
settings.updated
Board display settings were changed.
Trigger: Updating settings via API, CLI, MCP, or the UI.
Example payload:
{
"event": "settings.updated",
"timestamp": "2026-02-24T13:25:00.000Z",
"data": {
"showPriorityBadges": true,
"showAssignee": true,
"showDueDate": true,
"showLabels": true,
"compactMode": true,
"showFileName": false,
"defaultPriority": "medium",
"defaultStatus": "backlog"
}
}
Board Events
board.created
A new board was created.
Trigger: Creating a board via API, CLI, or MCP.
Example payload:
{
"event": "board.created",
"timestamp": "2026-02-24T14:00:00.000Z",
"data": {
"id": "bugs",
"name": "Bug Tracker",
"description": "Track production bugs"
}
}
board.updated
A board configuration was changed.
Trigger: Updating board name, description, or columns.
Example payload:
{
"event": "board.updated",
"timestamp": "2026-02-24T14:05:00.000Z",
"data": {
"id": "bugs",
"name": "Bug Tracker v2"
}
}
board.deleted
A board was deleted.
Trigger: Deleting an empty board via API, CLI, or MCP.
Example payload:
{
"event": "board.deleted",
"timestamp": "2026-02-24T14:10:00.000Z",
"data": {
"id": "bugs"
}
}