Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
ClickUp API integration with managed OAuth. Access tasks, lists, folders, spaces, workspaces, users, and manage webhooks. Use this skill when users want to manage work items, track projects, or integrate with ClickUp workflows. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
ClickUp API integration with managed OAuth. Access tasks, lists, folders, spaces, workspaces, users, and manage webhooks. Use this skill when users want to manage work items, track projects, or integrate with ClickUp workflows. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
Access the ClickUp API with managed OAuth authentication. Manage tasks, lists, folders, spaces, workspaces, users, and webhooks for work management.
# List workspaces (teams) python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
https://gateway.maton.ai/clickup/{native-api-path} Replace {native-api-path} with the actual ClickUp API endpoint path. The gateway proxies requests to api.clickup.com and automatically injects your OAuth token.
All requests require the Maton API key in the Authorization header: Authorization: Bearer $MATON_API_KEY Environment Variable: Set your API key as MATON_API_KEY: export MATON_API_KEY="YOUR_API_KEY"
Sign in or create an account at maton.ai Go to maton.ai/settings Copy your API key
Manage your ClickUp OAuth connections at https://ctrl.maton.ai.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=clickup&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'clickup'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "connection": { "connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80", "status": "ACTIVE", "creation_time": "2025-12-08T07:20:53.488460Z", "last_updated_time": "2026-01-31T20:03:32.593153Z", "url": "https://connect.maton.ai/?session_token=...", "app": "clickup", "metadata": {} } } Open the returned url in a browser to complete OAuth authorization.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If you have multiple ClickUp connections, specify which one to use with the Maton-Connection header: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF If omitted, the gateway uses the default (oldest) active connection.
ClickUp organizes data in a hierarchy: Workspace (team) โ Space โ Folder โ List โ Task Note: In the API, Workspaces are referred to as "teams".
Get Authorized Workspaces GET /clickup/api/v2/team Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "teams": [ { "id": "1234567", "name": "Acme Corp", "color": "#7B68EE", "avatar": null, "members": [ { "user": { "id": 123, "username": "Alice Johnson", "email": "alice@acme.com" } } ] } ] }
Get Spaces GET /clickup/api/v2/team/{team_id}/space Query parameters: archived - Include archived spaces (true/false) Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team/1234567/space') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "spaces": [ { "id": "90120001", "name": "Engineering", "private": false, "statuses": [ {"status": "to do", "type": "open"}, {"status": "in progress", "type": "custom"}, {"status": "done", "type": "closed"} ] } ] } Get a Space GET /clickup/api/v2/space/{space_id} Create a Space POST /clickup/api/v2/team/{team_id}/space Example: python <<'EOF' import urllib.request, os, json data = json.dumps({'name': 'New Space', 'multiple_assignees': True, 'features': {'due_dates': {'enabled': True}, 'time_tracking': {'enabled': True}}}).encode() req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team/1234567/space', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Update a Space PUT /clickup/api/v2/space/{space_id} Delete a Space DELETE /clickup/api/v2/space/{space_id}
Get Folders GET /clickup/api/v2/space/{space_id}/folder Query parameters: archived - Include archived folders (true/false) Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/space/90120001/folder') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "folders": [ { "id": "456789", "name": "Sprint 1", "orderindex": 0, "hidden": false, "space": {"id": "90120001", "name": "Engineering"}, "task_count": "12", "lists": [] } ] } Get a Folder GET /clickup/api/v2/folder/{folder_id} Create a Folder POST /clickup/api/v2/space/{space_id}/folder Example: python <<'EOF' import urllib.request, os, json data = json.dumps({'name': 'New Folder'}).encode() req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/space/90120001/folder', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Update a Folder PUT /clickup/api/v2/folder/{folder_id} Delete a Folder DELETE /clickup/api/v2/folder/{folder_id}
Get Lists GET /clickup/api/v2/folder/{folder_id}/list Query parameters: archived - Include archived lists (true/false) Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/folder/456789/list') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "lists": [ { "id": "901234", "name": "Backlog", "orderindex": 0, "status": {"status": "active", "color": "#87909e"}, "task_count": 25, "folder": {"id": "456789", "name": "Sprint 1"} } ] } Get Folderless Lists GET /clickup/api/v2/space/{space_id}/list Get a List GET /clickup/api/v2/list/{list_id} Create a List POST /clickup/api/v2/folder/{folder_id}/list Example: python <<'EOF' import urllib.request, os, json data = json.dumps({'name': 'New List'}).encode() req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/folder/456789/list', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Create Folderless List POST /clickup/api/v2/space/{space_id}/list Update a List PUT /clickup/api/v2/list/{list_id} Delete a List DELETE /clickup/api/v2/list/{list_id}
Get Tasks GET /clickup/api/v2/list/{list_id}/task Query parameters: archived - Include archived tasks (true/false) page - Page number (0-indexed) order_by - Sort by field (created, updated, due_date) reverse - Reverse sort order (true/false) subtasks - Include subtasks (true/false) statuses[] - Filter by status include_closed - Include closed tasks (true/false) assignees[] - Filter by assignee IDs due_date_gt - Due date greater than (Unix ms) due_date_lt - Due date less than (Unix ms) Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/list/901234/task?include_closed=true') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "tasks": [ { "id": "abc123", "name": "Implement login feature", "status": {"status": "in progress", "type": "custom", "color": "#4194f6"}, "priority": {"id": "2", "priority": "high", "color": "#f9d900"}, "due_date": "1709251200000", "assignees": [{"id": 123, "username": "Alice Johnson", "email": "alice@acme.com"}], "description": "Add OAuth login flow", "date_created": "1707436800000", "date_updated": "1708646400000" } ] } Get a Task GET /clickup/api/v2/task/{task_id} Query parameters: custom_task_ids - Use custom task IDs (true/false) team_id - Required when using custom_task_ids include_subtasks - Include subtasks (true/false) Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/task/abc123') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Create a Task POST /clickup/api/v2/list/{list_id}/task Content-Type: application/json { "name": "Task name", "description": "Task description", "assignees": [123], "status": "to do", "priority": 2, "due_date": 1709251200000, "tags": ["api", "backend"], "parent": null } Fields: name (required) - Task title description - Task description (supports markdown) assignees - Array of user IDs status - Status name (must match a status in the list) priority - Priority level (1=urgent, 2=high, 3=normal, 4=low, null=none) due_date - Unix timestamp in milliseconds due_date_time - Include time in due date (true/false) start_date - Unix timestamp in milliseconds time_estimate - Time estimate in milliseconds tags - Array of tag names parent - Parent task ID (for subtasks) custom_fields - Array of custom field objects Example: python <<'EOF' import urllib.request, os, json data = json.dumps({'name': 'Complete API integration', 'description': 'Integrate with the new payment API', 'priority': 2, 'due_date': 1709251200000, 'assignees': [123]}).encode() req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/list/901234/task', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Update a Task PUT /clickup/api/v2/task/{task_id} Example: python <<'EOF' import urllib.request, os, json data = json.dumps({'status': 'complete', 'priority': None}).encode() req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/task/abc123', data=data, method='PUT') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Delete a Task DELETE /clickup/api/v2/task/{task_id} Get Filtered Team Tasks GET /clickup/api/v2/team/{team_id}/task Query parameters: page - Page number (0-indexed) order_by - Sort field statuses[] - Filter by statuses assignees[] - Filter by assignees list_ids[] - Filter by list IDs space_ids[] - Filter by space IDs folder_ids[] - Filter by folder IDs
Get Current User GET /clickup/api/v2/user Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/user') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "user": { "id": 123, "username": "Alice Johnson", "email": "alice@acme.com", "color": "#7B68EE", "profilePicture": "https://...", "initials": "AJ", "week_start_day": 0, "timezone": "America/New_York" } }
Get Webhooks GET /clickup/api/v2/team/{team_id}/webhook Example: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team/1234567/webhook') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Create Webhook POST /clickup/api/v2/team/{team_id}/webhook Content-Type: application/json { "endpoint": "https://example.com/webhook", "events": ["taskCreated", "taskUpdated", "taskDeleted"], "space_id": "90120001", "folder_id": "456789", "list_id": "901234", "task_id": "abc123" } Events: taskCreated, taskUpdated, taskDeleted taskPriorityUpdated, taskStatusUpdated taskAssigneeUpdated, taskDueDateUpdated taskTagUpdated, taskMoved taskCommentPosted, taskCommentUpdated taskTimeEstimateUpdated, taskTimeTrackedUpdated listCreated, listUpdated, listDeleted folderCreated, folderUpdated, folderDeleted spaceCreated, spaceUpdated, spaceDeleted goalCreated, goalUpdated, goalDeleted keyResultCreated, keyResultUpdated, keyResultDeleted Example: python <<'EOF' import urllib.request, os, json data = json.dumps({'endpoint': 'https://example.com/webhook', 'events': ['taskCreated', 'taskUpdated']}).encode() req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/team/1234567/webhook', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "id": "webhook123", "webhook": { "id": "webhook123", "userid": 123, "team_id": "1234567", "endpoint": "https://example.com/webhook", "client_id": "...", "events": ["taskCreated", "taskUpdated"], "health": {"status": "active", "fail_count": 0}, "secret": "..." } } Update a Webhook PUT /clickup/api/v2/webhook/{webhook_id} Delete a Webhook DELETE /clickup/api/v2/webhook/{webhook_id}
ClickUp uses page-based pagination. Use the page parameter (0-indexed): python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/clickup/api/v2/list/901234/task?page=0') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Responses are limited to 100 tasks per page. The response includes a last_page boolean field. Continue incrementing the page number until last_page is true.
const response = await fetch( 'https://gateway.maton.ai/clickup/api/v2/list/901234/task', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const data = await response.json();
import os import requests response = requests.get( 'https://gateway.maton.ai/clickup/api/v2/list/901234/task', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) data = response.json()
Task IDs are strings Timestamps are Unix milliseconds Priority values: 1=urgent, 2=high, 3=normal, 4=low, null=none Workspaces are called "teams" in the API Status values must match the exact status names configured in the list Responses are limited to 100 items per page IMPORTANT: When using curl commands, use curl -g when URLs contain brackets (statuses[], assignees[], list_ids[]) to disable glob parsing IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.
StatusMeaning400Bad request or missing ClickUp connection401Invalid or missing Maton API key403Forbidden - insufficient permissions404Resource not found429Rate limited4xx/5xxPassthrough error from ClickUp API
Check that the MATON_API_KEY environment variable is set: echo $MATON_API_KEY Verify the API key is valid by listing connections: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Ensure your URL path starts with clickup. For example: Correct: https://gateway.maton.ai/clickup/api/v2/team Incorrect: https://gateway.maton.ai/api/v2/team
ClickUp API Overview Get Tasks Create Task Update Task Delete Task Get Spaces Get Lists Create Webhook Custom Fields Rate Limits LLM Reference Maton Community Maton Support
Workflow acceleration for inboxes, docs, calendars, planning, and execution loops.
Largest current source with strong distribution and engagement signals.