In Zendesk, setting the regular ticket status only updates the status category such as new, open, pending, hold, or solved. If your workflow relies on custom statuses, you must update the custom_status_id field instead.
This is useful when syncing from platforms like Jira, Azure DevOps, or others into Zendesk, and you want the ticket to reflect a specific custom status rather than only its generic status category.
Script Overview
1. Retrieve the available Zendesk custom statuses
The script calls:
/api/v2/custom_status
This returns all custom statuses configured in Zendesk, including fields such as:
-
id -
status_category -
agent_label -
description -
active
2. Map the incoming Exalate status to a Zendesk custom status label
Instead of mapping directly to the numeric ID, the script maps the incoming status to the Zendesk agent_label.
3. Update the Zendesk ticket using custom_status_id
Once the matching custom status is found, the script updates the ticket with a PUT request.
Final Solution
Zendesk Incoming sync
def statusLabelMap = [
'New' : 'Hold',
'Active' : 'Hold',
'In QA' : 'Hold',
'Waiting for customer' : 'Pending',
'Ready for QA' : 'Hold',
'Ready to Deploy' : 'Hold',
'Closed' : 'Solved'
]
def desiredLabel = statusLabelMap[replica.status?.name]
if (desiredLabel) {
def customStatusesResponse = httpClient.get("/api/v2/custom_statuses.json")
def customStatuses = customStatusesResponse?.custom_statuses ?: []
def matchedStatus = customStatuses.find { cs ->
cs.active && cs.agent_label?.toString()?.equalsIgnoreCase(desiredLabel)
}
def desiredCustomStatusId = matchedStatus?.id as Long
if (desiredCustomStatusId) {
def currentTicket = httpClient.get("/api/v2/tickets/${issue.key}.json")
def currentCustomStatusId = currentTicket?.ticket?.custom_status_id as Long
if (currentCustomStatusId != desiredCustomStatusId) {
httpClient.put(
"/api/v2/tickets/${issue.key}.json",
"""{
"ticket": {
"custom_status_id": ${desiredCustomStatusId}
}
}"""
)
}
}
}
Zendesk Outgoing sync
def ticket = httpClient.get("/api/v2/tickets/${issue.key}.json")
def currentStatusId = ticket?.ticket?.custom_status_id as Long
if (currentStatusId) {
def customStatuses = httpClient.get("/api/v2/custom_statuses.json")?.custom_statuses ?: []
def matchedStatus = customStatuses.find { (it.id as Long) == currentStatusId }
replica.status = matchedStatus?.agent_label
}
Alternative simpler approach
If you prefer, you can still use a direct ID mapping like this:
def statusMap = [
'New' : 23181153952276,
'Active' : 23181153952276,
'In QA' : 23181153952276,
'Waiting for customer' : 14559538794898,
'Ready for QA' : 23181153952276,
'Ready to Deploy' : 23181153952276,
'Closed' : 14559538794898
]
That works fine, but the label-based approach is usually easier to read and maintain.
Version
Tested on Version 5.32.1