Skip to main content

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-plugin package
  • Registrations stored in .kanban.json and persist across restarts
Register a webhook
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.delivery provider, ensuring consistent behavior regardless of entry point.
  • The default runtime provider id is webhooks, which resolves to the external kl-webhooks-plugin package.
  • kl-webhooks-plugin owns runtime delivery plus the standalone /api/webhooks routes, kl webhooks CLI 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-plugin registers the public webhook tools via the narrow mcpPlugin seam.
  • Webhook registrations are stored in .kanban.json and 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.json webhooks array; no migration is required.
  • A workspace that only configures webhookPlugin still activates webhook package discovery for provider, standalone, CLI, and MCP surfaces.
  • This file is generated from source metadata; do not edit docs/webhooks.md by 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 2xx responses 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"
  }
}