ClickUp Production Setup
This is the operator runbook for connecting a ClickUp workspace to a production Alakai deployment: discovering custom field IDs, registering list-scoped webhooks, storing secrets, and using the core/ utility Makefile to do it.
It assumes the platform/stage routing model (tasks trigger on the Alakai Ready status, routed by list/Platform field). For the config.json schema and local testing, see ClickUp Integration. For the end-user view, see ClickUp Automations.
All make commands below run from the core/ directory. Each reads CLICKUP_BOT_API_TOKEN, CLICKUP_WORKSPACE_ID, and ALAKAI_WEBHOOK_URL from arguments or from core/.env if not passed explicitly.
Prerequisites
| Item | How to get it |
|---|---|
| ClickUp bot API token | In ClickUp: Settings → Apps → API → generate a personal API token. Used for all webhook/field admin calls and for posting comments back on tasks. Store as CLICKUP_BOT_API_TOKEN. |
| Workspace (team) ID | The numeric ID in any ClickUp URL: https://app.clickup.com/<workspaceId>/.... Store as CLICKUP_WORKSPACE_ID. |
| Alakai public URL | The internet-reachable base URL of the deployed Alakai service (no trailing path). ClickUp posts webhooks to <url>/clickup/webhook. Store as ALAKAI_WEBHOOK_URL. |
Production environment variables
In production, Alakai loads its secrets from AWS Secrets Manager (AWS_SECRETS_MANAGER_SECRET_ID + AWS_REGION). The ClickUp-related keys:
| Variable | Required for | Description |
|---|---|---|
CLICKUP_BOT_API_TOKEN | Webhooks + comment-back | Bot token used to register webhooks and post comments on tasks. |
CLICKUP_WEBHOOK_SECRETS | Webhook signature verification | JSON object mapping webhook_id → secret, e.g. {"wh_abc123":"secret_..."}. One entry per registered list webhook. |
ALAKAI_WEBHOOK_URL | Webhook registration | Public base URL used as the webhook endpoint. |
CLICKUP_OAUTH_CLIENT_ID | /clickup-ask, /clickup-task | OAuth client registered with mcp.clickup.com (see OAuth client). |
CLICKUP_OAUTH_CLIENT_SECRET | /clickup-ask, /clickup-task | OAuth client secret (if issued). |
CLICKUP_OAUTH_REDIRECT_URI | /clickup-ask, /clickup-task | OAuth callback URL; must match the registered redirect URI. |
CLICKUP_SHARED_ACCESS_TOKEN | @Alakai thread → task | Shared token used by the thread-mention task-creation flow. |
CLICKUP_MCP_OPENAI_KEY | /clickup-ask, /clickup-task | OpenAI key for the ClickUp ask/task agent. |
CLICKUP_WORKSPACE_ID | Optional | Passed to MCP tools that accept a workspace ID. |
CLICKUP_AGENT_MODEL | Optional | Model for the ClickUp agent (default gpt-4o). |
CLICKUP_REDIS_KEY_PREFIX | Optional | Namespaces ClickUp OAuth/shared-token Redis keys. |
AWS_SECRETS_MANAGER_SECRET_ID | Production | Secrets Manager secret holding the above. Also required so /init can persist new webhook secrets. |
CLICKUP_WEBHOOK_SECRETSis stored as a JSON object (not a plain string). When adding a new list webhook, merge its{id: secret}entry into the existing object rather than overwriting it.
Step 1 — Configure the ClickUp UI
Before wiring config, set up the workspace in ClickUp so the routing fields exist:
Alakai Readystatus — add a status namedAlakai Readyto the workflow of each list Alakai watches. Moving a task into this status is the trigger.Alakai stagefield — create a dropdown custom field namedAlakai stagewith two options:PromptingandImplementation. (Matched by name, case-insensitive.)- Platform field (only for shared lists) — if one list feeds several repos, create a dropdown custom field (commonly named
Platform) whose options correspond to each target repo, e.g.Backend,iOS,Web.
Step 2 — Discover custom field IDs and option labels
config.json references the Platform field by its field ID, and routes by its option labels. List them for a given list:
cd core
make get-clickup-list-fields list_id=901200100
Output looks like:
Platform [id=cf_8a1b...] (type=drop_down)
- "Backend" orderindex=0 id=...
- "iOS" orderindex=1 id=...
Alakai stage [id=cf_9c2d...] (type=drop_down)
- "Prompting" orderindex=0 id=...
- "Implementation" orderindex=1 id=...
Use the Platform field's id as platformField.id and the option names (Backend, iOS, …) as each application's platformFieldValue in config.json.
Finding the list ID itself: open the list in ClickUp; the numeric ID is in the URL, or list them via the API —
curl -s "https://api.clickup.com/api/v2/space/<spaceId>/list?archived=false" -H "Authorization: $CLICKUP_BOT_API_TOKEN" | jq '.lists[] | {id, name}'.
Step 3 — Register a list-scoped webhook
Each connected list needs its own webhook for taskStatusUpdated events:
cd core
make register-clickup-webhook \
CLICKUP_BOT_API_TOKEN=pk_xxxxxxxxxxxxx \
CLICKUP_WORKSPACE_ID=3030784 \
ALAKAI_WEBHOOK_URL=https://alakai.example.com \
list_id=901200100
The command prints the ClickUp response and a ready-to-paste secret line:
Store this secret in the CLICKUP_WEBHOOK_SECRETS map (AWS Secrets Manager), keyed by webhook id:
"wh_abc123xyz789": "secret_xxxxxxxxxxxxxxxxxxxx"
Record the webhook ID — it goes into config.json as the list's webhookId (the routing key).
Step 4 — Store the webhook secret
Merge the printed {webhookId: secret} entry into the CLICKUP_WEBHOOK_SECRETS JSON object in the AWS Secrets Manager secret referenced by AWS_SECRETS_MANAGER_SECRET_ID:
{
"CLICKUP_WEBHOOK_SECRETS": "{\"wh_abc123xyz789\":\"secret_xxxxxxxxxxxxxxxxxxxx\",\"wh_def456\":\"secret_yyyy\"}"
}
Redeploy / restart Alakai so it picks up the updated secret. Signature verification fails (401) for any webhook whose ID is not present in this map.
Step 5 — Wire config.json
Add the list (with its webhookId, and platformField/defaultApplication if shared) under the project's clickup.lists[], and point each application at the list via taskStatusTrigger. Enable workflows.clickupTaskPromptPr: true on each application.
See ClickUp Integration → Configuring routing for the full schema and worked examples.
Optional — Register the OAuth client (for /clickup-ask & /clickup-task)
The Slack ClickUp commands authenticate each user against ClickUp's MCP OAuth server. Register a client once:
cd core
make register-clickup-mcp-client \
redirect_uri='https://alakai.example.com/oauth/clickup/callback' \
client_name='Alakai'
It prints the CLICKUP_OAUTH_CLIENT_ID to store. The redirect URI must exactly match CLICKUP_OAUTH_REDIRECT_URI.
The client must be registered with
mcp.clickup.com, not the legacyapp.clickup.com. Aclient_idfromapp.clickup.comwill not work.
Managing webhooks
List every webhook registered for the workspace (id, endpoint, scope, events, delivery health):
cd core
make list-clickup-webhooks \
CLICKUP_BOT_API_TOKEN=pk_xxxxxxxxxxxxx \
CLICKUP_WORKSPACE_ID=3030784
Use this to audit which lists are wired and to spot webhooks whose health is failing. Remove a stale or rotated webhook by ID:
cd core
make remove-clickup-webhook webhook_id='wh_abc123xyz789'
After removing a webhook, also drop its entry from CLICKUP_WEBHOOK_SECRETS.
Rotating a webhook secret
ClickUp does not rotate a webhook secret in place — delete and re-register:
make remove-clickup-webhook webhook_id='<old-id>'make register-clickup-webhook ... list_id=<listId>→ capture the new id + secret- Update both
CLICKUP_WEBHOOK_SECRETS(new entry, remove old) and the list'swebhookIdinconfig.json - Redeploy.
Utility Makefile reference
All run from core/:
| Target | Purpose |
|---|---|
make get-clickup-list-fields list_id=<id> | List a list's custom fields — IDs + dropdown option labels — for platformField config. |
make register-clickup-webhook ... list_id=<id> | Register a list-scoped taskStatusUpdated webhook; prints the webhook id + secret. |
make list-clickup-webhooks | List all workspace webhooks with scope, events, and health. |
make remove-clickup-webhook webhook_id=<id> | Delete a webhook by ID. |
make register-clickup-mcp-client redirect_uri=<uri> | Register the OAuth client for /clickup-ask and /clickup-task. |
Related docs
- ClickUp Integration —
config.jsonrouting schema + local testing - ClickUp Automations — user-facing behavior of the flow