Webhooks

Receive real-time HTTP callbacks when events happen on your boards through the AgentKanban API.


What are webhooks?

When something changes via the External API -- a task is created, a lane is renamed, a board is deleted -- AgentKanban can send an HTTP POST to a URL you choose. This lets you build integrations that react instantly: post to Slack, sync with an issue tracker, trigger a deploy, or log activity.


How webhooks and API keys relate

Every webhook is linked to an API key. The API key is not sent to your endpoint -- it is used to determine which boards the webhook receives events for.

Each API key has board grants (e.g. read or edit access to specific boards). When an event occurs on a board, only webhooks whose linked API key has a grant for that board will fire. This means:


Setting up via the UI

  1. Go to Settings > API Keys (admin or owner role required)
  2. Scroll to the Webhooks section
  3. Click Add webhook
  4. Select which API key to link the webhook to. This controls scope: the webhook will only fire for events on boards that key has access to. The key itself is not sent to your endpoint.
  5. Enter the Payload URL -- must use a publicly reachable http:// or https:// URL. HTTPS is strongly recommended.
  6. Choose All events or uncheck it to pick specific event types
  7. Click Add webhook

A signing secret (whsec_...) is shown once. Copy it immediately.


Setting up via the API

POST /api/ext/v1/webhooks
Authorization: Bearer ak_YourKey
Content-Type: application/json

{
  "url": "https://example.com/webhooks/agentkanban",
  "events": ["task.created", "task.updated"]
}

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

Response (201):

{
  "data": {
    "id": "01abc...",
    "url": "https://example.com/webhooks/agentkanban",
    "events": ["task.created", "task.updated"],
    "active": true,
    "secret": "whsec_abc123..."
  }
}

The secret is returned only on creation. Store it securely.


Event types

Event When it fires
board.created A board is created
board.deleted A board is deleted
lane.created A lane is created
lane.updated A lane is renamed or reordered
lane.deleted A lane is deleted
task.created A task is created
task.updated A task title, description, priority, tags, or archive status changes
task.deleted A task is deleted
task.moved A task moves to a different lane or position
comment.created A comment is added through the external API
comment.deleted A comment is deleted through the external API
todo.created A todo is added through the external API
todo.updated A todo is updated through the external API
todo.deleted A todo is deleted through the external API

Current note:


Payload format

Every webhook delivery sends a JSON POST body:

{
  "id": "evt_01abc...",
  "type": "task.created",
  "timestamp": "2025-07-15T10:30:00.000Z",
  "data": {
    "board_id": "01abc...",
    "task_id": "01def...",
    "title": "Fix login bug",
    "laneId": "01ghi..."
  }
}

The data object varies by event type. It always includes board_id and the relevant resource IDs.

Example payloads

board.created

{
  "id": "evt_...",
  "type": "board.created",
  "timestamp": "2025-07-15T10:30:00.000Z",
  "data": { "board_id": "...", "board": { "id": "...", "name": "Sprint 42" } }
}

task.moved

{
  "id": "evt_...",
  "type": "task.moved",
  "timestamp": "2025-07-15T10:31:00.000Z",
  "data": { "board_id": "...", "task_id": "...", "laneId": "...", "position": 0 }
}

lane.updated

{
  "id": "evt_...",
  "type": "lane.updated",
  "timestamp": "2025-07-15T10:32:00.000Z",
  "data": { "board_id": "...", "lane_id": "...", "name": "In Review" }
}

HTTP headers

Each delivery includes these headers:

Header Description
Content-Type application/json
X-AgentKanban-Signature-256 HMAC-SHA256 signature for verification
X-AgentKanban-Event Event type (e.g. task.created)
X-AgentKanban-Delivery Unique delivery ID
User-Agent AgentKanban-Webhooks/1.0

Verifying signatures

Every delivery is signed with HMAC-SHA256 using your webhook's signing secret. Always verify signatures to confirm the request came from AgentKanban.

The signature is in the X-AgentKanban-Signature-256 header, formatted as sha256=<hex>.

Node.js

import crypto from "crypto";

function verifySignature(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}

// In your Express/Fastify handler:
app.post("/webhooks/agentkanban", (req, res) => {
  const signature = req.headers["x-agentkanban-signature-256"];
  const rawBody = req.rawBody; // ensure you have access to the raw body

  if (!verifySignature(rawBody, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(rawBody);
  console.log(`Received ${event.type}:`, event.data);
  res.sendStatus(200);
});

Python

import hmac, hashlib

def verify_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature_header, expected)

# In your Flask handler:
@app.route("/webhooks/agentkanban", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-AgentKanban-Signature-256", "")
    if not verify_signature(request.data, signature, WEBHOOK_SECRET):
        return "Invalid signature", 401

    event = request.json
    print(f"Received {event['type']}: {event['data']}")
    return "", 200

Retry behaviour

If your endpoint returns a non-2xx status code or does not respond within 10 seconds, the delivery is retried with increasing delays:

Attempt Delay after failure
2nd 1 minute
3rd 5 minutes
4th 30 minutes
5th 2 hours

After 5 failed attempts, the delivery is marked as permanently failed. You can view delivery history via the API:

GET /api/ext/v1/webhooks/:id

The response includes recent_deliveries showing status, attempt count, and response details.


Managing webhooks

Via the UI

Via the API

Method Endpoint Description
GET /api/ext/v1/webhooks List all webhooks for this key
GET /api/ext/v1/webhooks/:id Detail with recent deliveries
PATCH /api/ext/v1/webhooks/:id Update URL, events, or active state
DELETE /api/ext/v1/webhooks/:id Delete a webhook

Update example:

PATCH /api/ext/v1/webhooks/:id
Content-Type: application/json

{ "events": ["task.created", "task.moved"], "active": true }

Response:

{ "data": { "id": "...", "url": "...", "events": ["task.created", "task.moved"], "active": true } }

Troubleshooting

Webhook not firing?

Getting 401 on signature verification?

Deliveries stuck as "pending"?

URL rejected on creation?