Stitchflow
Zendesk logo

Zendesk User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 6, 2026

Summary and recommendation

The Zendesk REST API (`https://{subdomain}.zendesk.com/api/v2`) supports full user lifecycle management via Basic Auth (email/token) or OAuth 2.0 Bearer Token. Granular OAuth scopes (`users:read`, `users:write`) are preferred over broad `read`/`write` scopes for production integrations.

Rate limits are enforced per subdomain - not per API key - so all integrations on an account share a single quota (200–700 req/min depending on plan tier), and HTTP 429 responses include a `Retry-After` header.

For identity graph construction, the `external_id` field is the correct anchor for mapping Zendesk user records to upstream HR or IdP identities. It must be unique per account; duplicate values return a 422.

Pair `external_id` with `last_login_at` (returned on `GET /api/v2/users`) to build an accurate, queryable picture of agent activity across your identity graph without relying on the admin UI's limited reporting.

API quick reference

Has user APIYes
Auth methodBasic Auth (email/token or email/password) or OAuth 2.0 Bearer Token
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise (Suite Enterprise or Support Enterprise). Note: Native SCIM is not available on lower tiers. Professional-tier accounts can use IdP API connector integrations (e.g., Okta, Entra ID) as a workaround.

Authentication

Auth method: Basic Auth (email/token or email/password) or OAuth 2.0 Bearer Token

Setup steps

  1. Basic Auth via API token: Enable API token access in Admin Center → Apps and Integrations → APIs → Zendesk API. Generate a token. Encode 'agent@example.com/token:{api_token}' in Base64 and pass as Authorization: Basic {encoded}.
  2. OAuth 2.0: Register an OAuth client in Admin Center → Apps and Integrations → APIs → OAuth Clients. Implement the authorization code flow to obtain a Bearer token. Pass as Authorization: Bearer {access_token}.
  3. Password auth (not recommended for production): Use email:password encoded as Basic Auth. Requires password auth to be enabled in Admin Center.

Required scopes

Scope Description Required for
read Read access to all resources including users. GET user endpoints
write Create and update access to resources including users. POST and PATCH user endpoints
users:read Granular read scope for user resources. GET user endpoints when using granular OAuth scopes
users:write Granular write scope for user resources. POST, PATCH, DELETE user endpoints when using granular OAuth scopes

User object / data model

Field Type Description On create On update Notes
id integer Unique Zendesk user ID. auto-assigned immutable Use this ID for all subsequent API calls referencing the user.
name string Full name of the user. required optional Max 255 characters.
email string Primary email address. required (for non-end-user roles) optional Must be unique across the account.
role string User role: 'end-user', 'agent', or 'admin'. optional (defaults to end-user) optional Changing to 'agent' or 'admin' consumes a seat license.
active boolean Whether the user account is active. auto (true) optional Set to false to deactivate (soft delete).
verified boolean Whether the user's primary identity is verified. optional optional Unverified users cannot log in.
suspended boolean Whether the user is suspended. optional optional Suspended users cannot log in or submit tickets.
organization_id integer ID of the user's primary organization. optional optional Use Organization Memberships API for multiple org membership.
external_id string Unique identifier from an external system. optional optional Useful for syncing with external identity providers. Must be unique if set.
alias string Agent alias displayed to end-users. optional optional Agents only.
phone string Primary phone number. optional optional E.164 format recommended.
time_zone string User's time zone (e.g., 'Pacific Time (US & Canada)'). optional optional Must match a Zendesk-supported time zone string.
locale string User's locale (e.g., 'en-US'). optional optional
tags array[string] Tags associated with the user. optional optional Replaces all existing tags on update unless using tag-specific endpoints.
custom_role_id integer ID of a custom agent role (Enterprise only). optional optional Only applicable when role is 'agent'.
user_fields object Key-value map of custom user field values. optional optional Keys are custom field keys defined in Admin Center.
created_at string (ISO 8601) Timestamp of user creation. auto-assigned immutable
updated_at string (ISO 8601) Timestamp of last update. auto-assigned auto-updated
last_login_at string (ISO 8601) Timestamp of last login. null system-managed
two_factor_auth_enabled boolean Whether 2FA is enabled for the user. read-only read-only Cannot be set via API.

Core endpoints

List Users

  • Method: GET
  • URL: /api/v2/users
  • Watch out for: Default returns all roles. Filter by role=agent|end-user|admin. Cursor pagination is preferred; legacy offset pagination is deprecated for large datasets.

Request example

GET /api/v2/users?role=agent&page[size]=100
Authorization: Basic {encoded}

Response example

{
  "users": [{"id": 123, "name": "Jane Doe", "email": "jane@example.com", "role": "agent"}],
  "meta": {"has_more": true, "after_cursor": "abc123"},
  "links": {"next": "https://example.zendesk.com/api/v2/users?page[after]=abc123"}
}

Show User

  • Method: GET
  • URL: /api/v2/users/{user_id}
  • Watch out for: Returns 404 if user is deleted (hard-deleted). Suspended or deactivated users still return 200.

Request example

GET /api/v2/users/123
Authorization: Basic {encoded}

Response example

{
  "user": {
    "id": 123,
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "agent",
    "active": true
  }
}

Create User

  • Method: POST
  • URL: /api/v2/users
  • Watch out for: Creating an agent or admin consumes a seat. If the email already exists, Zendesk returns the existing user (not an error) unless skip_verify_email is used carefully.

Request example

POST /api/v2/users
Content-Type: application/json

{"user": {"name": "John Smith", "email": "john@example.com", "role": "agent"}}

Response example

{
  "user": {
    "id": 456,
    "name": "John Smith",
    "email": "john@example.com",
    "role": "agent",
    "active": true,
    "created_at": "2024-01-15T10:00:00Z"
  }
}

Update User

  • Method: PUT
  • URL: /api/v2/users/{user_id}
  • Watch out for: Uses PUT but behaves as a partial update (only supplied fields are changed). PATCH is also accepted and behaves identically.

Request example

PUT /api/v2/users/456
Content-Type: application/json

{"user": {"name": "John A. Smith", "suspended": false}}

Response example

{
  "user": {
    "id": 456,
    "name": "John A. Smith",
    "suspended": false,
    "updated_at": "2024-01-16T09:00:00Z"
  }
}

Delete (Deactivate) User

  • Method: DELETE
  • URL: /api/v2/users/{user_id}
  • Watch out for: DELETE sets active=false (soft delete). The user record is retained. Hard deletion requires a separate GDPR-compliant deletion request via the Deletion API or Admin Center.

Request example

DELETE /api/v2/users/456
Authorization: Basic {encoded}

Response example

{
  "user": {
    "id": 456,
    "active": false,
    "name": "John A. Smith"
  }
}

Search Users

  • Method: GET
  • URL: /api/v2/users/search
  • Watch out for: Uses Zendesk search syntax. Results are eventually consistent. Max 1000 results returned. For exact lookups, prefer /api/v2/users?external_id= or /api/v2/users/show_many.

Request example

GET /api/v2/users/search?query=email:jane@example.com
Authorization: Basic {encoded}

Response example

{
  "users": [{"id": 123, "name": "Jane Doe", "email": "jane@example.com"}],
  "count": 1
}

Create or Update Many Users (Bulk)

  • Method: POST
  • URL: /api/v2/users/create_or_update_many
  • Watch out for: Accepts up to 100 users per request. Returns a job_status object; poll /api/v2/job_statuses/{id} to check completion. Failures for individual records are reported in job results, not as HTTP errors.

Request example

POST /api/v2/users/create_or_update_many
Content-Type: application/json

{"users": [{"name": "A", "email": "a@x.com"}, {"name": "B", "email": "b@x.com"}]}

Response example

{
  "job_status": {
    "id": "8b726e606741012ffc2d782bcb7848fe",
    "status": "queued",
    "url": "https://example.zendesk.com/api/v2/job_statuses/8b726e606741012ffc2d782bcb7848fe"
  }
}

Show Current User (Me)

  • Method: GET
  • URL: /api/v2/users/me
  • Watch out for: Useful for validating OAuth token identity and confirming the acting user's role and permissions.

Request example

GET /api/v2/users/me
Authorization: Bearer {access_token}

Response example

{
  "user": {
    "id": 789,
    "name": "API Bot",
    "role": "admin",
    "email": "bot@example.com"
  }
}

Rate limits, pagination, and events

  • Rate limits: Rate limits are enforced per subdomain and vary by plan. Limits apply to the total number of API requests per minute across all integrations on the account.
  • Rate-limit headers: Yes
  • Retry-After header: Yes
  • Rate-limit notes: When rate limited, the API returns HTTP 429. The Retry-After header indicates seconds to wait. Headers X-Rate-Limit and X-Rate-Limit-Remaining are returned on responses. Bulk endpoints (e.g., Create Many Users) count as a single request but have their own job-queue limits.
  • Pagination method: cursor
  • Default page size: 100
  • Max page size: 100
  • Pagination pointer: page[size] (cursor-based) or per_page + page (offset-based, legacy)
Plan Limit Concurrent
Suite Team / Support Team 200 requests/min 0
Suite Growth / Support Professional 400 requests/min 0
Suite Professional 400 requests/min 0
Suite Enterprise / Support Enterprise 700 requests/min 0
  • Webhooks available: Yes
  • Webhook notes: Zendesk supports webhooks (called 'Webhooks' in Admin Center) that can be triggered by triggers, automations, or directly via the Webhooks API. User-related events can be captured via triggers on ticket events that involve user changes, or via the Zendesk Events API for user-specific activity.
  • Alternative event strategy: For real-time user lifecycle events, use the Zendesk Sunshine Events API or poll the Users API with the updated_since filter parameter.
  • Webhook events: user.created (via Sunshine Events API), user.updated (via Sunshine Events API), Trigger-based: ticket created/updated when requester or assignee changes, Automation-based: time-based conditions on user-related ticket fields

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise (Suite Enterprise or Support Enterprise). Note: Native SCIM is not available on lower tiers. Professional-tier accounts can use IdP API connector integrations (e.g., Okta, Entra ID) as a workaround.

  • Endpoint: https://{subdomain}.zendesk.com/api/scim/v2

  • Supported operations: GET /Users – list users, GET /Users/{id} – retrieve user, POST /Users – create user, PUT /Users/{id} – replace user, PATCH /Users/{id} – update user, DELETE /Users/{id} – deactivate user, GET /Groups – list groups (organizations), POST /Groups – create group, PATCH /Groups/{id} – update group membership

Limitations:

  • Requires Enterprise plan; not available on Suite Team, Growth, or Professional natively.
  • SCIM provisioning maps to Zendesk organizations for group management, not custom roles.
  • Custom agent roles cannot be assigned via SCIM.
  • SCIM DELETE sets the user to inactive (soft delete), not hard delete.
  • Zendesk QA (formerly Klaus) is a separate product with its own SCIM endpoint.
  • SSO is not a prerequisite but is commonly configured alongside SCIM.

Common scenarios

Provisioning a new agent from an HR system: search first with GET /api/v2/users/search? query=email:{email} to avoid the silent duplicate behavior (a POST with an existing email returns HTTP 200 with the existing record, not a 409).

If not found, POST with role='agent' and external_id set to the HR system identifier. Be aware that role assignment to agent or admin immediately consumes a paid seat - a 422 is returned if the account is at seat limit, so check capacity before bulk provisioning.

Bulk deactivation for departed employees: use POST /api/v2/users/update_many with active: false for up to 100 users per request. This is a soft delete only - active is set to false and the record is retained. Poll GET /api/v2/job_statuses/{job_id} for completion; per-user failures surface in the job results array, not as HTTP errors. For GDPR hard deletion, a separate call to DELETE /api/v2/users/{id}/permanently is required after deactivation.

SCIM sync on Enterprise: native SCIM 2.0 is available at https://{subdomain}.zendesk.com/api/scim/v2 on Suite Enterprise only. A critical caveat: SCIM group push maps to Zendesk organizations, not agent groups or custom roles. Custom role assignment must be handled separately via the REST API post-provisioning. On sub-Enterprise plans, IdP API connector integrations (Okta, Entra ID) are the available workaround, requiring Professional tier ($115/agent/mo) and IdP-side configuration.

Provision a new agent from an external HR system

  1. Check if user exists: GET /api/v2/users/search?query=email:{email} to avoid duplicates.
  2. If not found, POST /api/v2/users with name, email, role='agent', external_id set to HR system ID.
  3. Assign to organization if needed: POST /api/v2/organization_memberships with user_id and organization_id.
  4. Optionally set custom user fields: included in the user POST body under user_fields key.
  5. Verify the response user.id and store it mapped to the HR system record for future updates.

Watch out for: Creating an agent immediately consumes a seat license. If the account is at seat limit, the API returns a 422 error. Check seat availability before bulk provisioning.

Bulk deactivate departed employees

  1. Build a list of external_ids or emails for departed users.
  2. For each user, GET /api/v2/users/search?query=external_id:{id} to resolve Zendesk user IDs.
  3. Batch update using POST /api/v2/users/update_many with {users: [{id: ..., active: false}, ...]} (max 100 per request).
  4. Poll /api/v2/job_statuses/{job_id} until status is 'completed'.
  5. Review job results array for any per-user failures and handle individually.

Watch out for: update_many sets active=false (soft delete). If hard deletion is required for GDPR compliance, use the separate User Deletion API endpoint DELETE /api/v2/users/{id}/permanently after deactivation.

Sync user profile updates from IdP via SCIM (Enterprise)

  1. Configure SCIM in Admin Center → Security → Team Member Authentication → SCIM.
  2. Copy the SCIM base URL (https://{subdomain}.zendesk.com/api/scim/v2) and generate a SCIM token.
  3. Enter the SCIM URL and token in the IdP (Okta, Entra ID, OneLogin) SCIM provisioning settings.
  4. Map IdP attributes to SCIM attributes: userName→email, displayName→name, active→active.
  5. Enable provisioning actions in IdP: Create Users, Update User Attributes, Deactivate Users.
  6. Run an initial import/sync in the IdP to reconcile existing users by email match.

Watch out for: SCIM group push maps to Zendesk organizations, not agent groups or custom roles. Custom role assignment must be done separately via the REST API after SCIM provisioning.

Why building this yourself is a trap

Several API behaviors deviate from standard REST conventions and will cause silent failures if not explicitly handled.

The PUT /api/v2/users/{id} endpoint behaves as a partial update despite its method - only supplied fields change - but the tags field is a full replacement on any PUT or PATCH; use the dedicated /api/v2/users/{id}/tags sub-resource for additive tag operations.

Cursor-based pagination (page[size]) is the current standard; legacy offset pagination (page= and per_page=) is deprecated for large datasets and may be removed. The GET /api/v2/users/search endpoint returns eventually consistent results and caps at 1,000 records - for exact lookups by external identity, prefer GET /api/v2/users?external_id= to ensure accuracy within your identity graph.

Bulk endpoints (create_or_update_many, update_many) are asynchronous and always require polling GET /api/v2/job_statuses/{id}. Treating the initial HTTP 200 response as confirmation of completion will cause missed failures.

Finally, DELETE /api/v2/users/{id} is a soft delete only; teams with GDPR obligations must implement a separate hard-deletion flow and should not assume the standard DELETE endpoint satisfies data removal requirements.

Automate Zendesk 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.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 6, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen