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.
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.
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.
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.
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.
Desk.tickets.READ,Desk.contacts.READ,Desk.tickets.CREATE. Set time duration to the maximum. Click Create and copy the grant code.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).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.
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 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.With the token stored as {{zoho_desk_token}} and the customer's email as {{customer_email}}, add a ticket search step:
| Field | Value | Notes |
|---|---|---|
| Select Method | GET | Fetching tickets for this requester email. |
| Request URL | https://desk.zoho.in/api/v1/tickets?email={{{customer_email}}}&status=open&limit=5&sortBy=-createdTime | India data centre: desk.zoho.in. email= filters to tickets from this contact. status=open shows open tickets only. sortBy=-createdTime gives newest first. |
| Authorization | Zoho-oauthtoken {{{zoho_desk_token}}} | The Zoho-specific auth header. Note: not 'Bearer'. Must match exactly. |
| orgId | 728000000123456 | Your Zoho Desk organisation ID from Step 3. Required on every API call. |
| Content-Type | application/json | Standard header for Zoho Desk API requests. |
| Status value | Meaning | Use in URL filter |
|---|---|---|
| open | Ticket is open and active | &status=open |
| onHold | Waiting on third party or agent | &status=onHold |
| pending | Waiting on customer response | &status=pending |
| closed | Ticket 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.
A successful Zoho Desk ticket search response looks like this:
{
"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].priorityZoho 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 name | Response path | Example value |
|---|---|---|
| ticket_number | data[0].ticketNumber | 1001 |
| ticket_subject | data[0].subject | Order #5521 not delivered |
| ticket_status | data[0].status | open |
| ticket_priority | data[0].priority | High |
| ticket_due | data[0].dueDate | 2026-06-24T10:30:00.000Z |
| ticket_count | count | 1 |
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.
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.
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:
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"}}]}}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."| Symptom | Likely cause | Fix |
|---|---|---|
| 401 with 'invalid_token' | Wrong auth header format | Use '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 error | orgId header not included | Add orgId: YOUR_ORG_ID as a header on every ticket/contact API call. Find your orgId via GET /api/v1/organizations. |
| Data centre mismatch | Using .zoho.com for Indian account | Change 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 email | Try without &status=open to check all tickets. Confirm the email is stored in Zoho Desk and matches exactly. |
| departmentId required when creating | POST /tickets missing department | Find your department IDs via GET /api/v1/departments. Include departmentId in your POST body. |
Zoho CRM: same Zoho-oauthtoken auth, India data centre, contact lookup by phone.
Read guide →Zendesk: OAuth 2.0 Bearer token, search tickets by email.
Read guide →Freshdesk: Basic Auth with API key, ticket lookup and creation.
Read guide →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.