Platform
Chatbot Builder Bulk Messaging Team Inbox Mini CRM API & Webhooks AI Integration WhatsApp Flows
Industries
E-commerce & D2C Real Estate Education Healthcare Finance & BFSI Logistics Hospitality Retail
Integrations
Learn
Learning Hub Help & Docs Connect Guides Automation Codex Blog Message Templates
Pricing Start Free Trial →
HomeConnect › Connect Zoho Desk to WhatsApp
Zoho Desk Integration Guide · Support / Helpdesk

Connect Zoho Desk to WhatsApp

Look up Zoho Desk support tickets from a WhatsApp chatbot by customer email, get ticket status and contact details, and create new tickets when customers describe a problem in chat. Zoho Desk is India's most widely used helpdesk alongside Freshdesk.

Published 23 June 2026  ·  8 min read  ·  Support / Helpdesk

Before following this guide, read the External API Request step foundation guide. It covers every field in the step interface so this guide can focus on Zoho Desk-specific values.

Auth header is Zoho-oauthtoken, not Bearer

All Zoho products use a custom Authorization header prefix. The format is: Authorization: Zoho-oauthtoken YOUR_TOKEN. Not 'Bearer'. This applies to Zoho Desk, Zoho CRM, Zoho Books and all other Zoho APIs. Using 'Bearer' returns a 401 error.

India data centre: use .zoho.in, not .zoho.com

If your Zoho account was created in India, your API and OAuth URLs must use the India data centre domain. For API calls: desk.zoho.in/api/v1/. For OAuth token requests: accounts.zoho.in/oauth/v2/token. Using .zoho.com from an Indian account causes data centre mismatch errors.

Step 1: Register an OAuth client and get your access token

Zoho Desk uses OAuth 2.0. For a server-to-server WhatsApp bot, the Self Client method is the simplest: no redirect URL or web app needed.

1
Go to api-console.zoho.in (India) and log in with your Zoho account.
2
Click Add ClientSelf Client. This creates a client credential pair without needing a redirect URL.
3
Copy your Client ID and Client Secret.
4
Under Generate Code, enter these scopes: Desk.tickets.READ,Desk.contacts.READ,Desk.tickets.CREATE. Set time duration to the maximum. Click Create and copy the grant code.
5
Exchange the grant code for tokens using the call below. This is a one-time step. The refresh token lasts permanently.
Exchange grant code for access and refresh tokens (one-time)
POST https://accounts.zoho.in/oauth/v2/token
Content-Type: application/x-www-form-urlencoded

Body (form fields):
  grant_type    = authorization_code
  client_id     = YOUR_CLIENT_ID
  client_secret = YOUR_CLIENT_SECRET
  code          = YOUR_GRANT_CODE

Response:
{
  "access_token": "1000.abc123...",
  "refresh_token": "1000.xyz789...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Store BOTH access_token and refresh_token.
The access token expires after 1 hour.
Use the refresh token to get a new access token (see Step 2).

Step 2: Refresh your access token (before each session)

Access tokens expire after one hour. Add a first External API Request step at the start of your chatbot flow to get a fresh token. Use the refresh token (which never expires) to do this.

External API Request Step 1 · Refresh Token
Select Method
POST
Request URL
https://accounts.zoho.in/oauth/v2/token?grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET
Select Body Type
None (parameters are in the URL)
Choose Response Type
JSON; map access_token as {{zoho_desk_token}}

Step 3: Get your organisation ID (one-time)

Every Zoho Desk API call (except this one) requires your orgId in the request header. Find it by calling the organisations endpoint once. No orgId header is needed for this specific call.

Get your Zoho Desk org ID (one-time lookup)
GET https://desk.zoho.in/api/v1/organizations
Authorization: Zoho-oauthtoken YOUR_ACCESS_TOKEN

Response:
{
  "data": [
    {
      "id": "728000000123456",
      "companyName": "Sharma Textiles",
      "portalName": "sharmatextiles",
      "edition": "PROFESSIONAL",
      "isAdminInOrg": true
    }
  ]
}

Copy the id value: 728000000123456
This is your orgId — add it to every subsequent API request header.

Step 4: Search tickets by customer email

With the token stored as {{zoho_desk_token}} and the customer's email as {{customer_email}}, add a ticket search step:

External API Request Step · WA.Expert
Select Method
GET
Request URL
https://desk.zoho.in/api/v1/tickets?email={{{{customer_email}}}}&status=open&limit=5&sortBy=-createdTime
Select Auth Type
No Auth (Zoho-oauthtoken in header below)
Header Parameters
AuthorizationZoho-oauthtoken {{{{zoho_desk_token}}}}
orgId728000000123456
Content-Typeapplication/json
Select Body Type
None (GET requests carry no body)
Choose Response Type
JSON

Field-by-field breakdown

FieldValueNotes
Select MethodGETFetching tickets for this requester email.
Request URLhttps://desk.zoho.in/api/v1/tickets?email={{{customer_email}}}&status=open&limit=5&sortBy=-createdTimeIndia data centre: desk.zoho.in. email= filters to tickets from this contact. status=open shows open tickets only. sortBy=-createdTime gives newest first.
AuthorizationZoho-oauthtoken {{{zoho_desk_token}}}The Zoho-specific auth header. Note: not 'Bearer'. Must match exactly.
orgId728000000123456Your Zoho Desk organisation ID from Step 3. Required on every API call.
Content-Typeapplication/jsonStandard header for Zoho Desk API requests.

Ticket status values

Status valueMeaningUse in URL filter
openTicket is open and active&status=open
onHoldWaiting on third party or agent&status=onHold
pendingWaiting on customer response&status=pending
closedTicket is resolved and closed&status=closed

Zoho Desk uses string status values (not numeric codes like Freshdesk). You can use the status string directly in a WhatsApp reply without conversion.

Step 5: Map the response to WhatsApp variables

A successful Zoho Desk ticket search response looks like this:

Zoho Desk API v1 — GET /tickets?email= response
{
  "data": [
    {
      "id": "728000000456789",
      "ticketNumber": "1001",
      "subject": "Order #5521 not delivered",
      "description": "My order placed on June 18 has not arrived.",
      "status": "open",
      "priority": "High",
      "contactId": "728000000234567",
      "departmentId": "728000000006907",
      "channel": "WhatsApp",
      "createdTime": "2026-06-20T10:30:00.000Z",
      "modifiedTime": "2026-06-22T14:00:00.000Z",
      "dueDate": "2026-06-24T10:30:00.000Z"
    }
  ],
  "count": 1
}

Map: data[0].ticketNumber, data[0].subject, data[0].status, data[0].priority
Results are in a data array under count

Zoho Desk wraps results in a 'data' array with a 'count' field. Map as data[0].subject, data[0].status. If count is 0 or data is empty, no open ticket was found for that email. Add a conditions branch for that case.

Map these response paths to variables in the External API Request step:

Variable nameResponse pathExample value
ticket_numberdata[0].ticketNumber1001
ticket_subjectdata[0].subjectOrder #5521 not delivered
ticket_statusdata[0].statusopen
ticket_prioritydata[0].priorityHigh
ticket_duedata[0].dueDate2026-06-24T10:30:00.000Z
ticket_countcount1

ticketNumber is the human-readable ticket number (#1001). id is the internal Zoho ID used in API calls. Use ticketNumber in customer-facing WhatsApp replies.

Keep the WhatsApp reply in the free service window

If the customer messaged you first within the last 24 hours, your reply is a free service conversation. For proactive outbound ticket updates, use an approved Utility template.

Bonus: create a Zoho Desk ticket from WhatsApp

When a customer describes a support issue in WhatsApp, your bot can create a Zoho Desk ticket automatically. You need a contactId (search contacts first) and a departmentId:

Create a Zoho Desk ticket — POST /api/v1/tickets
POST https://desk.zoho.in/api/v1/tickets
Authorization: Zoho-oauthtoken {{zoho_desk_token}}
orgId: 728000000123456
Content-Type: application/json

Body:
{
  "subject": "WhatsApp: {{customer_issue_summary}}",
  "description": "Customer message via WhatsApp:\n{{customer_message}}",
  "contactId": "{{contact_id}}",
  "departmentId": "YOUR_DEPARTMENT_ID",
  "priority": "Medium",
  "status": "open",
  "channel": "WhatsApp"
}

Response:
{ "id": "728000000456790", "ticketNumber": "1002", "status": "open" }

Bot replies:
"Ticket #{{ticket_number}} created. Our support team will
respond within 24 hours."

Find your departmentId: GET /api/v1/departments (same headers)
Returns: {{"data": [{{"id": "728000000006907", "name": "Support"}}]}}

Worked example: ticket status bot

Chatbot flow — Zoho Desk ticket lookup by email
Customer: "What is the status of my support ticket?"

Bot asks: "Please share the email used to submit the ticket."
Customer: priya@example.com
Stored as {{customer_email}}.

Step 1 — Refresh token:
POST https://accounts.zoho.in/oauth/v2/token
  ?grant_type=refresh_token
  &refresh_token=1000.xyz789...
  &client_id=...&client_secret=...
Store: zoho_desk_token = "1000.abc123..."

Step 2 — Search tickets:
GET https://desk.zoho.in/api/v1/tickets
  ?email=priya@example.com&status=open&limit=1
Authorization: Zoho-oauthtoken {{zoho_desk_token}}
orgId: 728000000123456

Response: count=1
ticket_number  = "1001"
ticket_subject = "Order #5521 not delivered"
ticket_status  = "open"
ticket_priority = "High"

Conditions: if count = 0 → "No open tickets found for this email."

Bot replies (if found):
"Hi Priya, here is your ticket update:

Ticket #1001: Order #5521 not delivered
Status: Open | Priority: High

Reply AGENT to request a callback, or CLOSE if resolved."

Troubleshooting

SymptomLikely causeFix
401 with 'invalid_token'Wrong auth header formatUse 'Zoho-oauthtoken YOUR_TOKEN', not 'Bearer'. Include a space after 'Zoho-oauthtoken'.
401 with 'token_expired'Access token expired (1-hour TTL)Re-request the token using your refresh token. Set up a token-refresh step at the start of each bot flow.
Missing orgId errororgId header not includedAdd orgId: YOUR_ORG_ID as a header on every ticket/contact API call. Find your orgId via GET /api/v1/organizations.
Data centre mismatchUsing .zoho.com for Indian accountChange desk.zoho.com to desk.zoho.in and accounts.zoho.com to accounts.zoho.in for Indian accounts.
Empty data array (count: 0)No open tickets for that emailTry without &status=open to check all tickets. Confirm the email is stored in Zoho Desk and matches exactly.
departmentId required when creatingPOST /tickets missing departmentFind your department IDs via GET /api/v1/departments. Include departmentId in your POST body.

Common questions

Why is the auth header Zoho-oauthtoken?
+
All Zoho products use this custom prefix, not 'Bearer'. Format: Authorization: Zoho-oauthtoken YOUR_TOKEN. Using 'Bearer' returns 401.
What is the orgId and where do I find it?
+
Your Zoho Desk organisation ID. Required on every API call. Find it once via GET /api/v1/organizations (no orgId header needed for this call only). Copy the id field from the first data item.
Which URLs should I use for India?
+
desk.zoho.in for API calls and accounts.zoho.in for OAuth token requests. Using .zoho.com from an Indian account returns data centre mismatch errors.
What are the ticket status values?
+
open, onHold, pending, closed. String values, not numeric. Filter with &status=open.
Can I search by customer email?
+
Yes: GET /api/v1/tickets?email=customer@example.com. Add &status=open for open tickets only.
Does this incur extra WA.Expert charges?
+
One automation action per External API Request call. Included on Complete plan. Starter: from Rs. 49 per 1,000 actions.

Connect Zoho Desk to WhatsApp today

Free trial, no credit card required. And if you ever get stuck, we are the only platform in India that answers you live on WhatsApp.

Start Free Trial → Book a Demo
1