ClickUp Integration
This guide covers both sides of the ClickUp integration for administrators and contributors:
- Configuring routing — wiring ClickUp lists, the Platform custom field, and the Alakai stage field into
config.json. - Testing locally — exercising the flow on your machine, from a quick signed mock to a full real-task round-trip.
For the end-user view of how the flow behaves, see ClickUp Automations.
Configuring routing
How the flow is triggered
Alakai listens for ClickUp taskStatusUpdated webhooks and acts only when a task transitions into the Alakai Ready status (case-insensitive). The routing key is the webhook ID: each connected list registers its own webhook, and Alakai uses the incoming webhook_id to find the list — and therefore the project — the task belongs to.
Resolution happens in this order:
- Webhook → list. Match the payload's
webhook_idagainstprojects.<project>.clickup.lists[].webhookId. No match → discarded (webhook_not_mapped). - List → application. Resolve which application (repo) the task targets — directly if the list has one app, or via the Platform custom field if it serves several (see below).
- Stage fork. Read the
Alakai stagecustom field to decide between the prompt-PR flow and direct implementation.
Throughout, the application must have workflows.clickupTaskPromptPr: true or the task is discarded.
Config schema
The relevant schema lives in core/src/config/repoWorkflowConfig.ts. The ClickUp-specific pieces:
Project level — projects.<project>.clickup:
| Field | Required | Description |
|---|---|---|
space.id | Yes | Numeric ClickUp space ID (string). |
space.name | No | Display name, used for logging and /clickup-task name matching. |
taskCreation.allowedSlackUserIds | No | Slack users allowed to use /clickup-task for this project. |
taskCreation.defaultListId | No | Default list for /clickup-task. |
lists[] | Yes (for this flow) | One entry per connected list — see below. |
List entry — projects.<project>.clickup.lists[]:
| Field | Required | Description |
|---|---|---|
id | Yes | Numeric ClickUp list ID (string). |
name | Yes | Human-readable list name. |
webhookId | Yes (for this flow) | The ClickUp webhook ID registered for this list. This is the routing key. |
platformField | Only when the list serves multiple apps | { id, name? } — the ClickUp custom field ID of the Platform dropdown. |
defaultApplication | No | Application key used when the Platform field is empty/unset on the task. |
Application level — projects.<project>.applications.<app>.clickup:
| Field | Required | Description |
|---|---|---|
taskStatusTrigger.listId | Yes (for this flow) | Must match a clickup.lists[].id in the same project. Associates this app with that list. |
taskStatusTrigger.platformFieldValue | Only on shared lists | The Platform dropdown option label that routes a task to this app (e.g. backend, ios). Matched case-insensitively. |
The application must also set workflows.clickupTaskPromptPr: true.
Example 1 — list mapped to a single repo
No Platform field needed. Every task in the list routes to the one application.
{
"projects": {
"demo": {
"displayName": "Demo Project",
"clickup": {
"space": { "id": "90120056789", "name": "Engineering" },
"lists": [
{
"id": "901200100",
"name": "Backlog",
"webhookId": "wh_abc123xyz789"
}
]
},
"applications": {
"demo-app": {
"repo": "your-org/your-repo",
"baseBranch": "main",
"workflows": { "clickupTaskPromptPr": true },
"clickup": {
"taskStatusTrigger": { "listId": "901200100" }
}
}
}
}
}
}
Example 2 — one list shared across repos (Platform routing)
The list carries a platformField, and each application declares the platformFieldValue that routes to it. defaultApplication handles tasks where the Platform field was left blank.
{
"projects": {
"demo": {
"clickup": {
"space": { "id": "90120056789", "name": "Engineering" },
"lists": [
{
"id": "901200100",
"name": "Backlog",
"webhookId": "wh_abc123xyz789",
"platformField": { "id": "cf_platform_field_id", "name": "Platform" },
"defaultApplication": "backend-app"
}
]
},
"applications": {
"backend-app": {
"repo": "your-org/backend-repo",
"baseBranch": "main",
"workflows": { "clickupTaskPromptPr": true },
"clickup": {
"taskStatusTrigger": { "listId": "901200100", "platformFieldValue": "backend" }
}
},
"ios-app": {
"repo": "your-org/ios-repo",
"baseBranch": "main",
"workflows": { "clickupTaskPromptPr": true },
"clickup": {
"taskStatusTrigger": { "listId": "901200100", "platformFieldValue": "ios" }
}
}
}
}
}
}
Application resolution rules
For a task arriving on a given list:
- List has no
platformField:- Exactly one app references the list via
taskStatusTrigger.listId→ route to it. - More than one →
ambiguous_application, discarded. - None →
no_application_for_list, discarded.
- Exactly one app references the list via
- List has a
platformField:- Read the task's value for that field ID and match its option label against each app's
platformFieldValue→ route to the match. - No match →
platform_not_mapped, discarded. - Field empty/unset and
defaultApplicationset → route to the default app. - Field empty/unset and no default →
platform_field_missing, discarded.
- Read the task's value for that field ID and match its option label against each app's
The Alakai stage field
The stage is read from a custom field named Alakai stage (case-insensitive lookup by name — it does not need to be declared in config.json).
| Value | Behaviour |
|---|---|
Prompting (or empty) | Generate a docs(prompts): clickup-<taskId> PR; merging it triggers the implementation pipeline. |
Implementation | Skip the prompt PR; enqueue a direct implementation run using the task description as the inline spec. |
Direct implementation requires a non-empty description and a spec under the inline payload limit (~230 KB). Otherwise Alakai posts a comment on the task explaining the problem and does not run.
Webhook registration & secrets
Each connected list needs its own ClickUp webhook, registered against POST /clickup/webhook. The webhook ID returned at registration goes into lists[].webhookId, and its signing secret is stored in the CLICKUP_WEBHOOK_SECRETS map (keyed by webhook ID) — in .env locally, or AWS Secrets Manager in production. The local testing guide walks through registering a webhook with ngrok.
Testing locally
To exercise the flow locally — a quick signed mock, or a full real-task round-trip with ngrok — see the dedicated guide: Test ClickUp "Alakai Ready" Flow Locally.
Related docs
- ClickUp Automations — user-facing overview of the ClickUp → prompt PR flow