Auto-Create Zoho Desk Tickets from a Zoho Creator Form

Auto-Create Zoho Desk Tickets from Zoho Creator

This script creates a Zoho Desk support ticket every time a record is submitted through a Zoho Creator form. It routes the ticket to a department based on a category picklist, carries the priority across, and writes the resulting ticket number and ID back onto the Creator record so the two systems stay linked.

It suits internal support request forms, bug report portals, and client feedback workflows — anywhere a Creator form is the intake and Desk is where the work actually gets tracked.

Before you start

  • A Zoho OAuth connection in Creator named zoho_desk_connection, with the Desk.tickets.CREATE scope. Setup → Connections → Create Connection → Zoho OAuth.
  • Your Desk department IDs. Fetch them once from https://desk.zoho.com/api/v1/departments and paste them into the routing block.
  • Creator fields: Subject, Description, Contact_Name, Contact_Email, Contact_Phone, Category (picklist), Priority (picklist).
  • Three write-back fields: Desk_Ticket_Number, Desk_Ticket_ID, API_Response (multi line, useful during testing).

Deluge script

// Trigger: On Success (after form submission in Creator)
// ============================================
// AUTO-CREATE ZOHO DESK TICKET FROM CREATOR
// ============================================

// Step 1: Sanitize user input for safe JSON embedding
rawSubject = ifnull(input.Subject, "No Subject");
rawDescription = ifnull(input.Description, "");
rawDescription = rawDescription.replaceAll("\n", " ");
rawDescription = rawDescription.replaceAll("\r", " ");
rawDescription = rawDescription.replaceAll("\"", "'");
rawDescription = rawDescription.replaceAll("\\\\", " ");
rawDescription = rawDescription.replaceAll("\t", " ");

contactName = ifnull(input.Contact_Name, "Unknown");
contactEmail = ifnull(input.Contact_Email, "");
contactPhone = ifnull(input.Contact_Phone, "");

// Step 2: Route to correct department based on picklist
deptId = "";
category = ifnull(input.Category, "General");
if(category == "Sales")
{
deptId = "YOUR_SALES_DEPT_ID";
}
else if(category == "Support")
{
deptId = "YOUR_SUPPORT_DEPT_ID";
}
else if(category == "Billing")
{
deptId = "YOUR_BILLING_DEPT_ID";
}
else
{
deptId = "YOUR_DEFAULT_DEPT_ID";
}

// Step 3: Set priority based on Creator field
ticketPriority = ifnull(input.Priority, "Medium");

// Step 4: Build JSON payload manually (nested Maps break invokeurl)
jsonStr = "{\"subject\":\"" + rawSubject + "\",";
jsonStr = jsonStr + "\"description\":\"" + rawDescription + "\",";
jsonStr = jsonStr + "\"departmentId\":\"" + deptId + "\",";
jsonStr = jsonStr + "\"priority\":\"" + ticketPriority + "\",";
jsonStr = jsonStr + "\"channel\":\"Web\",";
jsonStr = jsonStr + "\"contact\":{\"lastName\":\"" + contactName + "\",";
jsonStr = jsonStr + "\"email\":\"" + contactEmail + "\",";
jsonStr = jsonStr + "\"phone\":\"" + contactPhone + "\"}}";

// Step 5: Create the ticket via Zoho Desk API
createResponse = invokeurl
[
url: "https://desk.zoho.com/api/v1/tickets"
type: POST
parameters: jsonStr
headers: {"Content-Type": "application/json"}
connection: "zoho_desk_connection"
];

// Step 6: Safe response handling
respStr = createResponse.toString();
if(respStr.contains("ticketNumber"))
{
ticketNumber = createResponse.get("ticketNumber");
ticketId = createResponse.get("id");
input.Desk_Ticket_Number = ticketNumber;
input.Desk_Ticket_ID = ticketId;
input.API_Response = respStr;
info "Desk ticket created: " + ticketNumber;
}
else
{
input.API_Response = "ERROR: " + respStr;
info "Desk API error: " + respStr;
}

Why the JSON is built as a string

Zoho Desk’s ticket endpoint expects a nested contact object. Passing a Deluge Map that contains another Map to invokeurl does not reliably serialise the inner Map — it flattens or stringifies it, and the API rejects the payload. Building the JSON as a string sidesteps that entirely, which is why Step 4 looks the way it does.

That is also why Step 1 matters. Because the payload is hand-built, any unescaped quote, backslash, newline, or tab in user input will break the JSON. The sanitisation block strips them before they reach the string. Do not remove it.

Notes

  • Check the response, do not assume it. Step 6 tests for ticketNumber in the raw response rather than trusting the call succeeded. Storing the full response in a field during testing saves a lot of guessing.
  • Contacts are matched on email. Desk will reuse an existing contact when the email matches and create one when it does not.
  • On Success, not On Validate. The record needs to exist before you link a ticket to it.

This script is part of the free Creator Scripts Deluge Library.

All 39 Deluge scripts, the full Zoho Creator course, and every downloadable asset are now free. Get free access →