Summary and recommendation
ClickUp's REST API (v2, base URL https://api.clickup.com/api/v2) supports full user lifecycle management: invite, read, update, and remove workspace members. Auth is via Personal API Token or OAuth 2.0; critically, the Authorization header takes a raw token string - no 'Bearer' prefix.
The term 'team_id' throughout all API paths refers to the Workspace ID, not a sub-team; retrieve it first via GET /api/v2/team.
Rate limiting is enforced at 100 requests per minute per token. Response headers expose X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix timestamp). On 429, respect the Retry-After header before retrying - bulk invite loops will hit this ceiling quickly.
The user object includes a last_active field (ISO 8601), invite_pending boolean, role integer (1=Owner, 2=Admin, 3=Member, 4=Guest), and custom_role ID (Enterprise only). These fields are the foundation of any identity graph built on top of ClickUp membership data.
API quick reference
| Has user API | Yes |
| Auth method | Personal API Token or OAuth 2.0 |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: Personal API Token or OAuth 2.0
Setup steps
- Personal API Token: Log in to ClickUp → Settings → Apps → Generate API Token. Pass token in Authorization header as a raw string (not Bearer-prefixed).
- OAuth 2.0: Register an app at https://app.clickup.com/settings/integrations → OAuth Apps. Obtain client_id and client_secret. Redirect user to https://app.clickup.com/api?client_id={client_id}&redirect_uri={redirect_uri}. Exchange authorization code for access token via POST https://api.clickup.com/api/v2/oauth/token. Use returned access_token in Authorization header.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| read:user | Read authenticated user profile and workspace membership | Get Authorized User, Get User in Workspace |
| write:team | Invite and remove members from a workspace (team) | Invite User to Workspace, Remove User from Workspace |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique numeric user ID | system-assigned | immutable | Used as path parameter in user-scoped endpoints |
| username | string | Display name of the user | required | updatable | |
| string | Primary email address | required | updatable | Used as identifier for invitations | |
| color | string | User avatar color (hex) | optional | updatable | |
| profilePicture | string (URL) | URL of user's profile picture | optional | updatable | |
| initials | string | Auto-generated initials from username | system-assigned | immutable | |
| role | integer | Workspace role: 1=Owner, 2=Admin, 3=Member, 4=Guest | required (invite) | updatable | Numeric enum; Owner role cannot be assigned via API |
| custom_role | integer | null | ID of a custom role if assigned (Enterprise only) | optional | updatable | Requires Enterprise plan and custom roles feature |
| last_active | string (ISO 8601) | Timestamp of last user activity | system-assigned | immutable | |
| date_joined | string (ISO 8601) | Timestamp when user joined the workspace | system-assigned | immutable | |
| date_invited | string (ISO 8601) | Timestamp when invitation was sent | system-assigned | immutable | |
| invite_pending | boolean | True if user has not yet accepted the workspace invitation | system-assigned | immutable | |
| global_font_support | boolean | User preference for global font rendering | optional | updatable | |
| timezone | string | IANA timezone string (e.g. America/New_York) | optional | updatable |
Core endpoints
Get Authorized User
- Method: GET
- URL:
https://api.clickup.com/api/v2/user - Watch out for: Returns only the token owner's profile; cannot retrieve arbitrary users with this endpoint.
Request example
GET /api/v2/user
Authorization: pk_xxxx
Response example
{
"user": {
"id": 123,
"username": "Jane Doe",
"email": "jane@example.com",
"role": 2
}
}
Get Workspace Members
- Method: GET
- URL:
https://api.clickup.com/api/v2/team/{team_id}/member - Watch out for: team_id in ClickUp refers to the Workspace ID, not a sub-team. Guests may not appear depending on plan.
Request example
GET /api/v2/team/9011234567/member
Authorization: pk_xxxx
Response example
{
"members": [
{"user": {"id": 123, "email": "jane@example.com", "role": 2}},
{"user": {"id": 456, "email": "bob@example.com", "role": 3}}
]
}
Get User in Workspace
- Method: GET
- URL:
https://api.clickup.com/api/v2/team/{team_id}/member/{user_id} - Watch out for: Returns 404 if the user is not a member of the specified workspace.
Request example
GET /api/v2/team/9011234567/member/123
Authorization: pk_xxxx
Response example
{
"member": {
"user": {"id": 123, "email": "jane@example.com", "role": 2},
"invite_pending": false
}
}
Invite User to Workspace
- Method: POST
- URL:
https://api.clickup.com/api/v2/team/{team_id}/user - Watch out for: Caller must be Workspace Owner or Admin. Inviting guests requires the Guests & Permissions feature (paid plans).
Request example
POST /api/v2/team/9011234567/user
Authorization: pk_xxxx
Content-Type: application/json
{"email":"newuser@example.com","role":3}
Response example
{
"user": {
"id": 789,
"email": "newuser@example.com",
"role": 3,
"invite_pending": true
}
}
Update User in Workspace
- Method: PUT
- URL:
https://api.clickup.com/api/v2/team/{team_id}/user/{user_id} - Watch out for: Cannot promote a user to Owner (role 1) via API. Custom roles require Enterprise plan.
Request example
PUT /api/v2/team/9011234567/user/789
Authorization: pk_xxxx
Content-Type: application/json
{"role":2,"custom_role":null}
Response example
{
"user": {
"id": 789,
"role": 2
},
"team": {"id": "9011234567"}
}
Remove User from Workspace
- Method: DELETE
- URL:
https://api.clickup.com/api/v2/team/{team_id}/user/{user_id} - Watch out for: Permanently removes the user from the workspace. Action is irreversible via API; tasks assigned to the user are not automatically reassigned.
Request example
DELETE /api/v2/team/9011234567/user/789
Authorization: pk_xxxx
Response example
{}
Get Workspace (includes owner info)
- Method: GET
- URL:
https://api.clickup.com/api/v2/team - Watch out for: Returns only workspaces the authenticated token has access to. Member list in this response may be truncated; use /team/{id}/member for full list.
Request example
GET /api/v2/team
Authorization: pk_xxxx
Response example
{
"teams": [{
"id": "9011234567",
"name": "Acme Corp",
"members": [{"user": {"id": 1, "role": 1}}]
}]
}
Get Authorized Teams (OAuth)
- Method: GET
- URL:
https://api.clickup.com/api/v2/team - Watch out for: For OAuth apps, this returns only workspaces the authorizing user has granted access to, not all workspaces in the org.
Request example
GET /api/v2/team
Authorization: {oauth_access_token}
Response example
{
"teams": [{"id": "9011234567", "name": "Acme Corp"}]
}
Rate limits, pagination, and events
- Rate limits: ClickUp enforces per-token rate limits. The documented limit is 100 requests per minute per API token. Exceeding the limit returns HTTP 429.
- Rate-limit headers: Yes
- Retry-After header: Yes
- Rate-limit notes: Response headers include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix timestamp). On 429, respect Retry-After header before retrying.
- Pagination method: offset
- Default page size: 100
- Max page size: 100
- Pagination pointer: page
| Plan | Limit | Concurrent |
|---|---|---|
| All plans (Personal Token / OAuth) | 100 requests/minute per token | 0 |
- Webhooks available: Yes
- Webhook notes: ClickUp supports workspace-level webhooks that can fire on task, list, folder, space, and goal events. There are no dedicated user-lifecycle webhook events (e.g., member joined/removed) as of the current API v2.
- Alternative event strategy: Poll GET /api/v2/team/{team_id}/member periodically to detect membership changes, as no member-added/removed webhook event exists.
- Webhook events: taskCreated, taskUpdated, taskDeleted, taskMoved, taskCommentPosted, taskAssigneeUpdated, listCreated, listUpdated, listDeleted, folderCreated, folderUpdated, folderDeleted, spaceCreated, spaceUpdated, spaceDeleted, goalCreated, goalUpdated, goalDeleted
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Supported operations: GET /Users – list users, GET /Users/{id} – get user, POST /Users – provision (invite) user, PUT /Users/{id} – update user attributes, PATCH /Users/{id} – partial update / deactivate user, DELETE /Users/{id} – remove user from workspace, GET /Groups – list groups (spaces/teams), POST /Groups – create group, PATCH /Groups/{id} – update group membership
Limitations:
- Requires Enterprise plan and SSO (SAML) to be configured first
- Okta integration supports full provisioning including custom roles and team assignment
- Entra ID (Azure AD) integration supports user create and deactivate only; role and team assignment not supported via Entra SCIM
- SCIM bearer token is generated in ClickUp Security settings and does not expire automatically but should be rotated manually
- Groups in SCIM map to ClickUp user groups, not Spaces or Folders
- Deprovisioning sets user to inactive but does not delete task history
Common scenarios
Three primary automation scenarios are well-supported by the API:
Provisioning: POST /api/v2/team/{team_id}/user with the target email and role integer sends an invitation. The user must accept before appearing as active - poll GET /api/v2/team/{team_id}/member/{user_id} on invite_pending until false. Custom role assignment via PUT requires Enterprise.
Deprovisioning: Retrieve the user's numeric ID, optionally reassign tasks via PATCH /api/v2/task/{task_id} (assignees field), then DELETE /api/v2/team/{team_id}/user/{user_id}. This is immediate and irreversible via REST. On Enterprise with SCIM, prefer PATCH /Users/{id} with active:false to deactivate while preserving audit trail.
Bulk membership audit: Paginate GET /api/v2/team/{team_id}/member using zero-indexed page parameter (100 per page, no total_count field - stop when the returned array is empty or under 100). Map role integers to labels and flag invite_pending:true records as unaccepted invitations requiring follow-up.
Provision a new employee into ClickUp workspace
- Authenticate with a Personal API Token belonging to a Workspace Admin or Owner.
- POST /api/v2/team/{team_id}/user with {"email": "newuser@corp.com", "role": 3} to send an invitation.
- Poll GET /api/v2/team/{team_id}/member/{user_id} until invite_pending is false to confirm acceptance.
- Optionally PUT /api/v2/team/{team_id}/user/{user_id} to assign a custom_role (Enterprise only).
Watch out for: The user must accept the email invitation before they are fully active. Automations that depend on the user being active will fail if triggered before acceptance.
Deprovision a departing employee
- Retrieve the user's numeric ID via GET /api/v2/team/{team_id}/member or GET /api/v2/team/{team_id}/member/{user_id} using their email.
- Reassign open tasks via PATCH /api/v2/task/{task_id} (assignees field) before removal if needed.
- DELETE /api/v2/team/{team_id}/user/{user_id} to remove the user from the workspace.
- If on Enterprise with SCIM, prefer PATCH /Users/{id} with active:false via SCIM to deactivate without losing audit trail.
Watch out for: DELETE via REST API is immediate and irreversible. Tasks assigned to the removed user are NOT automatically reassigned; handle this before deletion.
Bulk audit workspace membership and roles
- GET /api/v2/team to retrieve all workspace IDs accessible to the token.
- For each workspace, GET /api/v2/team/{team_id}/member with page=0, incrementing page until an empty members array is returned (100 per page).
- Map role integers (1=Owner, 2=Admin, 3=Member, 4=Guest) to human-readable labels.
- Flag users where invite_pending=true as unaccepted invitations for follow-up.
Watch out for: Pagination uses zero-indexed page parameter. There is no total_count field in the response; stop when the returned members array is empty or has fewer than 100 items.
Why building this yourself is a trap
Personal API tokens are scoped to the generating user's account. If that user is removed from the workspace, every integration using their token breaks silently - a common failure mode in service-account-light environments. OAuth 2.0 is the safer path for production integrations but requires app registration and a redirect-based auth flow.
There are no webhook events for user membership changes (member joined, member removed). Real-time sync requires polling GET /api/v2/team/{team_id}/member on a schedule, which consumes rate limit budget. At 100 req/min per token, a pipeline that polls membership plus handles task reassignment and role updates will need careful request budgeting and exponential backoff.
SCIM (v2.0, endpoint https://app.clickup.com/scim/v2/{workspace_id}) is Enterprise-only and requires SAML SSO to be configured first. Entra ID SCIM supports user create and deactivate only - role and team assignment are not supported via that path. Okta delivers full provisioning including custom roles.
Any identity graph that relies on ClickUp role data for downstream access decisions must account for this IdP-specific gap when Entra is in use.
Automate ClickUp workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.