Stitchflow
Zoho Desk logo

Zoho Desk User Management API Guide

API workflow

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

UpdatedMar 17, 2026

Summary and recommendation

The Zoho Desk REST API (v1, base URL: `https://desk.zoho.com/api/v1`) uses OAuth 2.0 with short-lived access tokens (1-hour TTL) and requires refresh token rotation via `https://accounts.zoho.com/oauth/v2/token`.

All requests must include the `orgId` HTTP header when the OAuth token spans multiple Zoho organizations - omitting it returns a 400 or silently targets the wrong org.

Data-center routing is the caller's responsibility: EU orgs must use `desk.zoho.eu`, AU orgs `desk.zoho.com.au`, and so on.

The API does not support bulk operations;

every agent or contact create/update is a discrete HTTP call.

Pagination uses a 1-based `from` index with a maximum `limit` of 100 records per page.

Rate limits vary by plan but are not publicly documented per endpoint;

HTTP 429 is returned on breach, with no `Retry-After` header - implement exponential backoff.

For automated, IdP-driven provisioning at scale, SCIM 2.0 is available on Enterprise (and Zoho One) via Zoho Directory, with a separate bearer token distinct from the REST OAuth credential

this is the recommended path for building an identity graph that stays synchronized with your IdP.

API quick reference

Has user APIYes
Auth methodOAuth 2.0
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise

Authentication

Auth method: OAuth 2.0

Setup steps

  1. Register an application at https://api-console.zoho.com to obtain a Client ID and Client Secret.
  2. Choose the appropriate OAuth grant type (Authorization Code for user-context, Client Credentials for server-to-server).
  3. Request the required Zoho Desk scopes (e.g., Desk.contacts.READ, Desk.agents.READ) during authorization.
  4. Exchange the authorization code for an access token and refresh token via https://accounts.zoho.com/oauth/v2/token.
  5. Include the access token in the Authorization header as 'Zoho-oauthtoken {access_token}' on all API requests.
  6. Use the refresh token to obtain new access tokens before expiry (typically 1 hour).

Required scopes

Scope Description Required for
Desk.contacts.READ Read contact (end-user) records List/get contacts
Desk.contacts.WRITE Create and update contact records Create/update contacts
Desk.contacts.DELETE Delete contact records Delete contacts
Desk.agents.READ Read agent (support staff) records List/get agents
Desk.agents.WRITE Create and update agent records Create/update agents
Desk.settings.READ Read portal/organization settings including roles and departments Read roles, departments
Desk.settings.WRITE Modify portal/organization settings Update roles, departments

User object / data model

Field Type Description On create On update Notes
id string Unique system-generated identifier for the agent or contact auto-generated immutable Used as path parameter in all single-resource endpoints
firstName string First name of the agent or contact optional optional
lastName string Last name of the agent or contact required optional
email string Primary email address; used as login identifier for agents required for agents optional Must be unique per organization for agents
phone string Primary phone number optional optional
mobile string Mobile phone number optional optional
roleId string ID of the role assigned to the agent optional optional Agents only; references a role object
departmentIds array List of department IDs the agent belongs to optional optional Agents only
isActive boolean Whether the agent account is active optional (defaults true) optional Agents only; set false to deactivate
type string Agent license type (e.g., FULLTIME, LIGHT) optional optional Agents only; affects billing
accountId string ID of the account/company the contact belongs to optional optional Contacts only
description string Free-text description or notes about the contact optional optional Contacts only
twitter string Twitter handle of the contact optional optional Contacts only
createdTime datetime (ISO 8601) Timestamp when the record was created auto-generated immutable
modifiedTime datetime (ISO 8601) Timestamp of last modification auto-generated auto-updated

Core endpoints

List Agents

  • Method: GET
  • URL: https://desk.zoho.com/api/v1/agents
  • Watch out for: The orgId header is required on all requests when the OAuth token has access to multiple Zoho organizations.

Request example

GET /api/v1/agents?from=1&limit=50
Authorization: Zoho-oauthtoken {access_token}
orgId: {orgId}

Response example

{
  "data": [
    {"id":"123","firstName":"Jane","lastName":"Doe","email":"jane@example.com","isActive":true}
  ]
}

Get Agent

  • Method: GET
  • URL: https://desk.zoho.com/api/v1/agents/{agentId}
  • Watch out for: Returns 404 if the agent ID does not exist in the specified org.

Request example

GET /api/v1/agents/123
Authorization: Zoho-oauthtoken {access_token}
orgId: {orgId}

Response example

{
  "id":"123","firstName":"Jane","lastName":"Doe",
  "email":"jane@example.com","roleId":"456","isActive":true
}

Create Agent

  • Method: POST
  • URL: https://desk.zoho.com/api/v1/agents
  • Watch out for: Creating an agent sends an invitation email to the specified address. Agent seat limits apply per plan.

Request example

POST /api/v1/agents
Content-Type: application/json

{"firstName":"John","lastName":"Smith","email":"john@example.com","roleId":"456"}

Response example

{
  "id":"789","firstName":"John","lastName":"Smith",
  "email":"john@example.com","isActive":true
}

Update Agent

  • Method: PATCH
  • URL: https://desk.zoho.com/api/v1/agents/{agentId}
  • Watch out for: Only fields included in the request body are updated; omitted fields retain their current values.

Request example

PATCH /api/v1/agents/789
Content-Type: application/json

{"roleId":"999","isActive":false}

Response example

{
  "id":"789","firstName":"John","lastName":"Smith",
  "roleId":"999","isActive":false
}

List Contacts

  • Method: GET
  • URL: https://desk.zoho.com/api/v1/contacts
  • Watch out for: Contacts are end-users (customers), not agents. Use the /agents endpoint for support staff.

Request example

GET /api/v1/contacts?from=1&limit=100
Authorization: Zoho-oauthtoken {access_token}
orgId: {orgId}

Response example

{
  "data": [
    {"id":"321","firstName":"Alice","lastName":"Brown","email":"alice@customer.com"}
  ]
}

Create Contact

  • Method: POST
  • URL: https://desk.zoho.com/api/v1/contacts
  • Watch out for: Duplicate email addresses may be merged or rejected depending on org duplicate-check settings.

Request example

POST /api/v1/contacts
Content-Type: application/json

{"lastName":"Brown","firstName":"Alice","email":"alice@customer.com"}

Response example

{
  "id":"321","firstName":"Alice","lastName":"Brown",
  "email":"alice@customer.com","createdTime":"2024-01-15T10:00:00Z"
}

Update Contact

  • Method: PATCH
  • URL: https://desk.zoho.com/api/v1/contacts/{contactId}
  • Watch out for: Partial updates only; full replacement (PUT) is not supported for contacts.

Request example

PATCH /api/v1/contacts/321
Content-Type: application/json

{"phone":"+1-555-0100","accountId":"654"}

Response example

{
  "id":"321","firstName":"Alice","lastName":"Brown",
  "phone":"+1-555-0100","accountId":"654"
}

Delete Contact

  • Method: DELETE
  • URL: https://desk.zoho.com/api/v1/contacts/{contactId}
  • Watch out for: Deleting a contact is irreversible and may affect associated ticket history visibility.

Request example

DELETE /api/v1/contacts/321
Authorization: Zoho-oauthtoken {access_token}
orgId: {orgId}

Response example

HTTP 204 No Content

Rate limits, pagination, and events

  • Rate limits: Zoho Desk enforces API call limits per organization per day. The official documentation states limits vary by plan but does not publish per-endpoint per-second limits publicly.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: Official docs do not explicitly document rate-limit response headers or Retry-After behavior. HTTP 429 is returned when limits are exceeded. Consult Zoho Desk API documentation for current plan-specific limits.
  • Pagination method: offset
  • Default page size: 50
  • Max page size: 100
  • Pagination pointer: from (1-based start index) and limit (page size)
Plan Limit Concurrent
Free Not publicly documented 0
Standard Not publicly documented 0
Professional Not publicly documented 0
Enterprise Not publicly documented 0
  • Webhooks available: Yes
  • Webhook notes: Zoho Desk supports webhooks (called 'Notifications' in the UI) that send HTTP POST payloads to a configured URL when specified events occur.
  • Alternative event strategy: Zoho Desk also supports Automation Rules and Workflow rules that can trigger HTTP actions, usable as a webhook alternative for some event types.
  • Webhook events: ticket.created, ticket.updated, ticket.statusChanged, contact.created, contact.updated, agent.created, agent.updated

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise

  • Endpoint: Provisioned via Zoho Directory; the SCIM base URL is generated within the Zoho Directory SCIM configuration panel and is specific to the connected IdP integration. No single static public endpoint is documented.

  • Supported operations: Create user (POST /Users), Read user (GET /Users/{id}), Update user (PUT /Users/{id}), Deactivate user (PATCH /Users/{id} with active:false), List users (GET /Users)

Limitations:

  • SCIM provisioning requires SAML SSO to be configured first in Zoho Directory.
  • Enterprise plan (or Zoho One) is required; not available on Free, Standard, or Professional plans.
  • SCIM is managed through Zoho Directory, not directly through the Zoho Desk API.
  • Group/role provisioning support via SCIM is not explicitly documented in official sources.
  • The SCIM bearer token is generated in Zoho Directory and is separate from the Zoho Desk OAuth token.

Common scenarios

Three integration patterns cover the primary lifecycle operations.

To provision a new agent: obtain a token with Desk.agents.WRITE and Desk.settings.READ, resolve roleId via GET /api/v1/roles and departmentIds via GET /api/v1/departments, then POST /api/v1/agents

note that this immediately triggers an invitation email with no documented suppression mechanism.

To deactivate a departing agent: PATCH /api/v1/agents/{agentId} with {"isActive": false};

open ticket reassignment is not automatic and must be handled separately via ticket update endpoints or automation rules.

To sync contacts from an external CRM: paginate GET /api/v1/contacts?from=1&limit=100 to build a local index keyed by email, then upsert via PATCH or POST

duplicate-check behavior on email is org-configurable, so validate in a sandbox before running against production.

Provision a new support agent

  1. Obtain an OAuth 2.0 access token with Desk.agents.WRITE and Desk.settings.READ scopes.
  2. GET /api/v1/roles to retrieve available role IDs and identify the correct roleId.
  3. GET /api/v1/departments to retrieve department IDs if department assignment is needed.
  4. POST /api/v1/agents with firstName, lastName, email, roleId, and departmentIds in the request body.
  5. Store the returned agent id for future update or deactivation operations.

Watch out for: Agent creation sends an invitation email automatically. Ensure the email address is correct before calling the API; there is no undo for the invitation.

Deactivate a departing agent

  1. Obtain an OAuth 2.0 access token with Desk.agents.WRITE scope.
  2. GET /api/v1/agents to find the agent's id by email if not already known.
  3. PATCH /api/v1/agents/{agentId} with body {"isActive": false} to deactivate the account.
  4. Verify the response confirms isActive is false.

Watch out for: Deactivation via API does not automatically reassign open tickets. Ticket reassignment must be handled separately via ticket update endpoints or automation rules.

Sync contacts from an external CRM

  1. Obtain an OAuth 2.0 access token with Desk.contacts.READ and Desk.contacts.WRITE scopes.
  2. GET /api/v1/contacts?from=1&limit=100 and paginate through all pages to build a local index of existing contacts keyed by email.
  3. For each CRM contact: if email exists in index, PATCH /api/v1/contacts/{id} with changed fields; otherwise POST /api/v1/contacts to create.
  4. Handle 429 responses by backing off and retrying; Zoho does not document a Retry-After header so use exponential backoff.

Watch out for: Duplicate-check behavior on email is org-configurable. Test in a sandbox org first to confirm whether duplicate emails are rejected or silently merged.

Why building this yourself is a trap

The most common integration failure points are auth and identity graph drift. Access tokens expire after 1 hour; missing refresh rotation causes silent failures in long-running sync jobs.

The orgId header omission is a frequent source of cross-org data leakage in multi-tenant OAuth apps. SCIM provisioning runs through Zoho Directory - not the Desk REST API - meaning the SCIM bearer token, SCIM base URL, and supported operations (including PATCH /Users/{id} with active:false for deactivation) are all managed outside the Desk API surface;

teams that conflate the two auth systems end up with incomplete deprovision coverage in their identity graph. Group and role provisioning support via SCIM is not explicitly documented, so role assignment may require a follow-up REST API call after SCIM user creation.

Finally, deactivating an agent via isActive: false in the REST API does not guarantee immediate seat release - billing state is governed separately by Zoho's subscription system.

Automate Zoho Desk 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 17, 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