ClickUp Upgrade & Migration
Overview
Guide for migrating between ClickUp API versions. API v2 is the current stable version (/api/v2/). API v3 endpoints are gradually being introduced with terminology and structural changes.
Key v2 vs v3 Terminology Changes
| Concept | API v2 Term | API v3 Term |
|---|---|---|
| Workspace | Team (team_id) |
Workspace (workspace_id) |
| User Group | Team | Group (group_id) |
| Get workspaces | GET /team |
GET /v3/workspaces |
Pre-Migration Assessment
#!/bin/bash
# Audit current ClickUp API usage
echo "=== ClickUp API Usage Audit ==="
# Find all API v2 calls in codebase
echo "API v2 endpoints found:"
grep -rn "api/v2/" src/ --include="*.ts" --include="*.js" | \
sed 's/.*api\/v2\///' | cut -d'"' -f1 | cut -d"'" -f1 | \
sort | uniq -c | sort -rn
# Count unique endpoints
echo ""
echo "Unique endpoints:"
grep -rohn "api/v2/[a-z_/]*" src/ --include="*.ts" | sort -u
# Check for deprecated patterns
echo ""
echo "Deprecated patterns:"
grep -rn "team_id\|getauthorizedteams" src/ --include="*.ts" -i || echo " None found"
Migration Strategy: Adapter Pattern
// src/clickup/adapter.ts
// Abstract away API version so you can swap v2 -> v3 per-endpoint
interface ClickUpAdapter {
getWorkspaces(): Promise<Workspace[]>;
getSpaces(workspaceId: string): Promise<Space[]>;
createTask(listId: string, task: CreateTaskInput): Promise<Task>;
}
class ClickUpV2Adapter implements ClickUpAdapter {
async getWorkspaces() {
const data = await this.request('/team');
return data.teams.map((t: any) => ({ id: t.id, name: t.name }));
}
async getSpaces(workspaceId: string) {
const data = await this.request(`/team/${workspaceId}/space`);
return data.spaces;
}
async createTask(listId: string, task: CreateTaskInput) {
return this.request(`/list/${listId}/task`, {
method: 'POST',
body: JSON.stringify(task),
});
}
private async request(path: string, options?: RequestInit) {
const res = await fetch(`https://api.clickup.com/api/v2${path}`, {
...options,
headers: {
'Authorization': process.env.CLICKUP_API_TOKEN!,
'Content-Type': 'application/json',
},
});
return res.json();
}
}
// When v3 endpoints are available, add:
class ClickUpV3Adapter implements ClickUpAdapter {
async getWorkspaces() {
// v3 uses /v3/workspaces instead of /v2/team
const data = await this.request('/workspaces');
return data.workspaces;
}
// ... implement other methods with v3 endpoints
}
Feature Flag for Gradual Migration
function getAdapter(): ClickUpAdapter {
const useV3 = process.env.CLICKUP_API_V3 === 'true';
return useV3 ? new ClickUpV3Adapter() : new ClickUpV2Adapter();
}
// All calling code uses the adapter interface
const adapter = getAdapter();
const workspaces = await adapter.getWorkspaces();
Testing Migration
import { describe, it, expect } from 'vitest';
describe('API Version Migration', () => {
const adapters = [
{ name: 'v2', adapter: new ClickUpV2Adapter() },
// Uncomment when v3 adapter is ready:
// { name: 'v3', adapter: new ClickUpV3Adapter() },
];
adapters.forEach(({ name, adapter }) => {
it(`${name}: returns workspaces with id and name`, async () => {
const workspaces = await adapter.getWorkspaces();
expect(workspaces[0]).toHaveProperty('id');
expect(workspaces[0]).toHaveProperty('name');
});
});
});
Rollback Procedure
# If v3 migration causes issues:
# 1. Set feature flag back to v2
export CLICKUP_API_V3=false
# 2. Verify v2 still works
curl -sf https://api.clickup.com/api/v2/user \
-H "Authorization: $CLICKUP_API_TOKEN" | jq '.user.username'
# 3. Redeploy with v2 adapter
Prerequisites
- Recorded source/target API contract and compatibility owner
- Pinned current adapter plus a feature flag and tested rollback path
- Representative staging fixtures and an isolated integration environment
- Approval for field semantic, data-retention, or permission changes
Instructions
Add the target adapter behind a feature flag, run contract tests against sanitized staging fixtures, and compare response mappings before routing live traffic. Promote in bounded increments with telemetry and retain the current adapter until the agreed validation window passes; unknown endpoints or fields must fail closed rather than silently using an incompatible fallback.
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Endpoint 404 | v3 endpoint not yet available | Fall back to v2 equivalent |
| Field name mismatch | v3 changed response shape | Update type definitions |
team_id not recognized |
v3 expects workspace_id |
Use adapter to translate |
Output
Produce a migration receipt with source/target behavior, adapter/version pins, contract-test results, field mapping decisions, rollout percentage, approvals, rollback proof, and owner. Keep tokens, private task data, and raw user responses out of the receipt.
Examples
Route a staging read operation through both adapters, compare the normalized ID and name fields, and preserve the v2 result as the baseline. If the v3 adapter changes a required field or authorization behavior, restore the v2 flag and correct the translation before increasing traffic.
Resources
Next Steps
For CI integration during upgrades, see clickup-ci-integration.