Webhooks Integration
This guide explains how to use the webhook endpoint, wire up handlers, and run the system locally or with a queue backend.
For endpoint shape and payload examples, see ClickUp Webhook Endpoint.
Event processing modes
The endpoint converts the incoming DTO to a domain event ClickUpWebhookEvent and forwards it to an Event Sink selected by QUEUE_BACKEND.
QUEUE_BACKEND=local- Uses
LocalEventSink, dispatches directly to in-process handlers via the registry.
- Uses
QUEUE_BACKEND=<backend>(e.g.kafka,redis)- Uses
QueueEventSinkfromabstract-backendto publish to topicclickup.webhooks. - A separate consumer process handles the events.
- Uses
Environment variables
QUEUE_BACKENDlocalfor in-process handling (default).- Any other supported backend name (provided by the
abstract-backendplugin) enables queue mode.
CLICKUP_WEBHOOK_HANDLER_MODULES- Comma-separated module list to import at startup. Importing registers handlers.
- Example:
CLICKUP_WEBHOOK_HANDLER_MODULES="myproj.clickup_handlers.oop,myproj.clickup_handlers.func"
Writing handlers
You can author handlers using either OOP or decorator style. Both register into the central registry and work in both modes.
OOP style
from clickup_mcp.web_server.event.handler.oop import BaseClickUpWebhookHandler
from clickup_mcp.web_server.event.models import ClickUpWebhookEvent
class MyHandler(BaseClickUpWebhookHandler):
async def on_task_status_updated(self, event: ClickUpWebhookEvent) -> None:
# your logic
...
async def on_task_created(self, event: ClickUpWebhookEvent) -> None:
...
Decorator style
from clickup_mcp.web_server.event.handler.decorators import clickup_event
from clickup_mcp.web_server.event.models.enums import ClickUpWebhookEventType
from clickup_mcp.web_server.event.models import ClickUpWebhookEvent, ClickUpWebhookContext
@clickup_event(ClickUpWebhookEventType.TASK_STATUS_UPDATED)
async def handle_status(evt: ClickUpWebhookEvent, ctx: ClickUpWebhookContext) -> None:
...
@clickup_event.task_created
async def handle_created(evt: ClickUpWebhookEvent, ctx: ClickUpWebhookContext) -> None:
...
Running locally
export QUEUE_BACKEND=local
export CLICKUP_WEBHOOK_HANDLER_MODULES="myproj.clickup_handlers.oop,myproj.clickup_handlers.func"
# Start your server (example CLI)
clickup-mcp-server --integrated --transport sse --port 8000
Running with a queue
Install and configure an abstract-backend queue plugin (e.g. Kafka/Redis) and set its env variables as required by the plugin.
- Webhook server (publishes to queue):
export QUEUE_BACKEND=kafka
export CLICKUP_WEBHOOK_HANDLER_MODULES="myproj.clickup_handlers.oop,myproj.clickup_handlers.func"
# plus plugin-specific env vars like brokers, credentials, etc.
clickup-mcp-server --integrated --transport sse --port 8000
- Consumer (subscribes and dispatches):
export QUEUE_BACKEND=kafka
export CLICKUP_WEBHOOK_HANDLER_MODULES="myproj.clickup_handlers.oop,myproj.clickup_handlers.func"
clickup-webhook-consumer --queue-backend kafka
Pluggable queue backends (abstract-backend)
This project uses the Python library abstract-backend to load a message queue backend at runtime. That means you can quickly swap the queue implementation without code changes.
- Switching backends is just package management + environment variables:
- Deprecate current backend:
pip uninstall <message-queue-backend> - Install a new backend:
pip install <message-queue-backend> - Point the system to it:
export QUEUE_BACKEND=<backend-name> - Provide any backend-specific environment variables (brokers, DSNs, creds), per the backend plugin.
- Deprecate current backend:
Quick switch example (Kafka → Redis)
# Remove Kafka backend plugin
pip uninstall abe-kafka
# Install Redis backend plugin
pip install abe-redis
# Tell the system to use Redis
export QUEUE_BACKEND=redis
# (Optional) Backend-specific envs, e.g. for Redis
export REDIS_URL=redis://localhost:6379/0
# Start server and consumer as usual
clickup-mcp-server --integrated --transport sse --port 8000
clickup-webhook-consumer --queue-backend "$QUEUE_BACKEND"
Notes:
QUEUE_BACKEND=localkeeps everything in-process (no external queue required).- Any non-
localvalue activates queue mode using the installedabstract-backendplugin. - Backend package names above are examples; consult your chosen plugin for exact names and environment variables.
- abstract-backend: A lightweight plugin framework that loads message queue backends at runtime. It exposes a simple publish/consume interface and selects the backend via environment (e.g.,
QUEUE_BACKEND). - abe-redis: A Redis-backed implementation for abstract-backend providing message queue semantics over Redis. Ideal for local dev or lightweight deployments.
Event types
Supported ClickUpWebhookEventType values include all task/list/folder/space/goal/keyResult events mirrored from ClickUp docs and fixtures, for example:
- Task:
taskCreated,taskUpdated,taskDeleted,taskStatusUpdated,taskAssigneeUpdated,taskDueDateUpdated,taskTagUpdated,taskMoved,taskCommentPosted,taskCommentUpdated,taskTimeEstimateUpdated,taskTimeTrackedUpdated,taskPriorityUpdated - List:
listCreated,listUpdated,listDeleted - Folder:
folderCreated,folderUpdated,folderDeleted - Space:
spaceCreated,spaceUpdated,spaceDeleted - Goal:
goalCreated,goalUpdated,goalDeleted - Key Result:
keyResultCreated,keyResultUpdated,keyResultDeleted