How to Create Macros to Automate Ticket Replies in Zoho Desk

Learn to enhance customer support efficiency by automating ticket replies in Zoho Desk. This guide will teach you how to create custom functions using OpenAI's GPT models to meet your business needs.

Published on October 10, 2024

Share This Post
Artboard 1

Introduction

Automating ticket replies can dramatically enhance your customer support efficiency, transforming your team into a paragon of productivity. Zoho Desk has great tools for managing customer inquiries. But, you may need to extend its functions to meet specific business needs. This guide will teach you to create custom functions in Zoho Desk. They will automate ticket replies using AI with OpenAI’s GPT models.

We’ll build three progressively advanced custom functions for Macros in Zoho Desk:

  1. Basic Custom Function: Automate adding a draft reply to a ticket.
  2. AI-Powered Reply Generation: Integrate OpenAI API to generate professional responses.
  3. Prompt Adjustment for AI Responses: Allow agents to refine AI replies with custom prompts.

This guide will give you a system that uses AI to improve your customer support workflow in Zoho Desk. It will generate responses to support requests.

 

Prerequisites

Before you begin, ensure you have the following:

  1. Zoho Desk Account: With admin access to create custom functions and macros.
  2. Zoho OAuth Client ID and Client Secret: For API authentication.
  • OpenAI API Key: To access OpenAI’s GPT models.
  1. Access to cURL or Postman: To make API calls and test API requests.

Part 1: Setting Up Zoho OAuth Authentication

To interact with Zoho Desk’s API, you need to authenticate using OAuth 2.0. This section guides you through obtaining the necessary tokens.

1.1. Obtain Zoho OAuth Credentials

First, you need to get your Client ID and Client Secret from Zoho.

Log in to Zoho Developer Console (https://api-console.zoho.com/) and click Get Started. Then, click Server-based Applications.

Image 1.1

Fill in the required details like Client Name (your application name), Homepage URL (your domain), and Authorized Redirect URIs (e.g., https://localhost – for testing purposes). Then, click Create.

Image 1.2

After creating the client, note down the Client ID and Client Secret.

1.2. Generate Authorization Code

You will need an Authorization Code to obtain an access token.

Construct the following URL in your browser:

https://accounts.zoho.com/oauth/v2/auth?scope=Desk.tickets.ALL&client_id=YOUR_CLIENT_ID&response_type=code&access_type=offline&redirect_uri=YOUR_REDIRECT_URI

Replace YOUR_CLIENT_ID with your actual Client ID. Then, replace YOUR_REDIRECT_URI with the Redirect URI you specified earlier. As we will be managing tickets in Zoho Desk, we will set the scope as ‘Desk.tickets.ALL’.

Image 1.3

Visit the URL in your browser. Log in if prompted. Then, authorize the app by clicking Accept.

Image 1.4

After authorization, you’ll be redirected to your Redirect URI. The URL will have a ‘code’ parameter. This is your Authorization Code.

Image 1.5

Remember, this code will only be valid for a short period. If the code expires, revisit the URL to get another code.

1.3. Exchange Authorization Code for Access Token

Now, exchange the Authorization Code for an Access Token and a Refresh Token.

Using cURL:

curl –request POST \

–url “https://accounts.zoho.com/oauth/v2/token” \

–data “grant_type=authorization_code&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&redirect_uri=YOUR_REDIRECT_URI&code=AUTHORIZATION_CODE”

Replace placeholders with actual values and run this command. You will get a reply with an Access Token and a Refresh Token.

Image 1.6

The Access Token is valid for only an hour. If it expires, or to auto-renew it in a custom function, use the Refresh Token.

Using Postman:

Open Postman and make a new POST request to https://accounts.zoho.com/oauth/v2/token.

Image 1.7

In the Body tab, select x-www-form-urlencoded and add the following keys:

  • grant_type: authorization_code
  • client_id: YOUR_CLIENT_ID
  • client_secret: YOUR_CLIENT_SECRET
  • redirect_uri: YOUR_REDIRECT_URI
  • code: AUTHORIZATION_CODE

Then, send the request.

Image 1.8

Expected Response:

The response will look something like;

{

“access_token”: “1000.xxxxxxxx”,

“refresh_token”: “1000.xxxxxxxx”,

“expires_in”: 3600,

“token_type”: “Bearer”

}

 

1.4. Refreshing the Access Token

Access tokens expire after a set time. Use the Refresh Token to obtain a new Access Token.

Using cURL:

curl –request POST \

–url “https://accounts.zoho.com/oauth/v2/token” \

–data “refresh_token=YOUR_REFRESH_TOKEN&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=refresh_token”

 

Image 1.9

Using Postman:

Create a new POST request to https://accounts.zoho.com/oauth/v2/token.

In the Body tab, add:

  • grant_type: refresh_token
  • client_id: YOUR_CLIENT_ID
  • client_secret: YOUR_CLIENT_SECRET
  • refresh_token: YOUR_REFRESH_TOKEN

Send the request to receive a new Access Token.

Image 1.10

 

Part 2: Creating the Basic Custom Function

Currently, Zoho Desk’s API doesn’t support creating draft replies directly. Attempting to include an ‘isDraft’ parameter in the API call results in an error.

As a workaround, we can use Private Comments as drafts. Private comments are visible only to agents and can be manually converted into public replies later.

2.1. Writing the Custom Function

Custom Function Code:

// Zoho Desk custom function to add a draft reply

// Input Variables: ‘ticketId’ (Ticket ID) and ‘replyContent’ (Message content)

ticketId = input.ticketId;

// Ticket ID

replyContent = input.replyContent;

// Message content to post as a reply

// Prepare the data for the draft reply

responseMap = Map();

responseMap.put(“content”,replyContent);

// The actual message content

responseMap.put(“isPublic”,true);

// Ensure the reply is public, not a private comment

// API endpoint to add a reply in Zoho Desk

zohoDeskURL = “https://desk.zoho.com/api/v1/tickets/” + ticketId + “/comments”;

// Set the headers for the API call

headersMap = Map();

headersMap.put(“Authorization”,”Zoho-oauthtoken YOUR_ACCESS_TOKEN”);

headersMap.put(“Content-Type”,”application/json”);

// Convert responseMap to JSON format before sending

responseBody = responseMap.toString();

// Make the POST API call to Zoho Desk to create the draft reply

response = postUrl(zohoDeskURL,responseBody,headersMap);

// Log the response for debugging purposes

info response;

 

Notes:

Replace YOUR_ACCESS_TOKEN with the Access Token obtained earlier.

This function adds a private comment to the ticket, serving as a draft.

2.2. Implementing the Function in a Macro

To automate this function, we’ll create a macro in Zoho Desk.

Log in to Zoho Desk. From Zoho Desk dashboard, go to Setup and click Macros under Automation.

Image 2.1

Click on Create Rule to create a new macro. Write Rule Name, enable Active, and click Next.

Image 2.2

Select agents who will have access to this macro. Under Add Actions, choose Custom Function and click New.

Image 2.3

Write a Function Name. Paste the custom function code and set the parameters. Map the Input Variables (ticketId and replyContent). Then, replace YOUR_ACCESS_TOKEN with actual Access Token.

Image 2.4

Click on Save Script and make sure the function is updated successfully. Then click Save. After creating the custom function for your macro, click Save.

Image 2.5

Go to tickets, click on a ticket, click Macros, and select the macro we just created to see if it executes as expected.

Image 2.6

 

Part 3: Extending the Function with OpenAI Integration

3.1. Obtaining OpenAI API Access

To use OpenAI’s GPT models, you need an API key. Visit the OpenAI Platform (https://platform.openai.com/signup) and Sign Up or Log In.

On OpenAI Platform, go to Dashboard, click API Keys, and Click Create new secret key.

Image 3.1

Select You under Owned by, Name your key, select a Project, and set Permissions to All. Then, click Create secret key.

Image 3.2

Keep this API key secured and do not share it with others.

3.2. Writing the AI-Powered Custom Function

This function fetches public messages from a ticket and uses OpenAI to generate a professional response.

Custom Function Code:

// Input Variables: ‘ticketId’, ‘agentName’ (logged-in user name)

ticketId = input.ticketId;

agentName = input.agentName;

// 1. Get public messages from the ticket

zohoDeskURL = “https://desk.zoho.com/api/v1/tickets/” + ticketId + “/comments”;

headersMap = Map();

headersMap.put(“Authorization”,”Zoho-oauthtoken YOUR_ZOHO_ACCESS_TOKEN “);

commentsResponse = getUrl(zohoDeskURL,headersMap);

commentsList = commentsResponse.get(“data”);

publicMessages = list();

// Filter only public comments and concatenate messages

ticketConversation = “”;

for each  comment in commentsList

{

if(comment.get(“isPublic”) == true)

{

ticketConversation = ticketConversation + comment.get(“content”) + “\n”;

// Concatenate with new line

}

}

// 2. Send data to OpenAI API to generate a response

openaiURL = “https://api.openai.com/v1/completions”;

headersMap.put(“Authorization”,”Bearer YOUR_OPENAI_API_KEY “);

openaiRequestBody = Map();

openaiRequestBody.put(“model”,”gpt-3.5-turbo”);

openaiRequestBody.put(“prompt”,”You are a helpdesk agent named ” + agentName + “. Read the messages in this ticket:\n” + ticketConversation + “\nCraft a professional response addressing the sender by name, but do not add a signature for yourself.”);

openaiRequestBody.put(“max_tokens”,150);

openaiResponse = postUrl(openaiURL,openaiRequestBody.toString(),headersMap);

openaiResponseContent = openaiResponse.get(“choices”).get(0).get(“text”);

// 3. Post the generated response as a private message in Zoho Desk

replyMap = Map();

replyMap.put(“content”,openaiResponseContent);

replyMap.put(“isPublic”,false);

// Send as private message

zohoDeskReplyURL = “https://desk.zoho.com/api/v1/tickets/” + ticketId + “/comments”;

responseBody = replyMap.toString();

replyResponse = postUrl(zohoDeskReplyURL,responseBody,headersMap);

// Log the response for debugging

info replyResponse;

 

Notes:

Replace YOUR_ZOHO_ACCESS_TOKEN and YOUR_OPENAI_API_KEY with your actual tokens.

Adjust the ‘model’ parameters if needed.

The function sends a professional reply as a private comment for agent review.

Create a new macro for this function in Zoho Desk by creating a new function (same as we did for the first function).

Image 3.3

Test by running the macro within a ticket in Zoho Desk.

Image 3.4

3.3. Testing the Function with Postman

Testing API calls in Postman ensures everything works before integrating into Zoho Desk.

Testing Zoho Desk API:

POST Request to Add a Comment:

  • URL: https://desk.zoho.com/api/v1/tickets/{ticketId}/comments

Headers:

  • Authorization: Zoho-oauthtoken YOUR_ZOHO_ACCESS_TOKEN
  • Content-Type: application/json

Body (raw JSON):

{

“content”: “This is a test comment from Postman”,

“isPublic”: true

}

 

Testing OpenAI API:

POST Request to Generate a Completion:

  • URL: https://api.openai.com/v1/completions

Headers:

  • Authorization: Bearer YOUR_OPENAI_API_KEY
  • Content-Type: application/json

Body (raw JSON):

{

“model”: “text-davinci-003”,

“prompt”: “You are a helpdesk agent. Please generate a test response for this prompt.”,

“max_tokens”: 150

}

 

 

Part 4: Adding Prompt Adjustments for AI Responses

Sometimes, the AI-generated response may not be perfect. We can enhance the function to allow agents to modify the prompt for better results.

4.1. Enhancing the Custom Function

This custom function will fetch the last private comment, which contains the AI-generated response from the previous custom function. If the agent wants to modify this response, they can edit the private comment and use ## delimiters to enclose the changes they require.

This custom function will then check for any text between these delimiters, treating it as a modified prompt. This prompt is then sent to the OpenAI API to generate a new response, which is subsequently posted as a private comment.

4.2. Writing the Enhanced Function

Custom Function Code:

// Input Variables: ‘ticketId’, ‘agentName’

ticketId = input.ticketId;

agentName = input.agentName;

 

// 1. Get all comments from the ticket

zohoDeskURL = “https://desk.zoho.com/api/v1/tickets/” + ticketId + “/comments”;

headersMap = Map();

headersMap.put(“Authorization”, “Zoho-oauthtoken YOUR_ZOHO_ACCESS_TOKEN”);

 

commentsResponse = getUrl(zohoDeskURL, headersMap);

if (commentsResponse.get(“status_code”) != 200) {

info “Error fetching comments: ” + commentsResponse;

return;

}

 

commentsList = commentsResponse.get(“data”);

if (commentsList.isEmpty()) {

info “No comments found for ticket ” + ticketId;

return;

}

 

// Initialize variable for storing the last private comment

lastPrivateComment = “”;

lastPrivateCommentTime = null;

 

// 2. Find the most recent private comment

for each comment in commentsList {

if (comment.get(“isPublic”) == false) {

commentTime = comment.get(“createdTime”);  // Get the comment time

if (lastPrivateCommentTime == null || commentTime > lastPrivateCommentTime) {

lastPrivateComment = comment.get(“content”);

lastPrivateCommentTime = commentTime;

}

}

}

 

// 3. Check for modifications in the last private comment

modifiedPrompt = “”;

if (lastPrivateComment.contains(“##”)) {

startIdx = lastPrivateComment.indexOf(“##”) + 2;

endIdx = lastPrivateComment.lastIndexOf(“##”);

 

// Ensure indices are valid before extracting the modified prompt

if (endIdx > startIdx) {

modifiedPrompt = lastPrivateComment.subString(startIdx, endIdx).trim();  // Use subString in Deluge

}

}

 

// 4. Prepare the prompt for OpenAI API

ticketConversation = “”;  // TODO: Append relevant ticket messages here

 

openaiRequestBody = Map();

openaiHeaders = Map();

openaiHeaders.put(“Authorization”, “Bearer YOUR_OPENAI_API_KEY”);  // Use original hardcoded OpenAI key

openaiHeaders.put(“Content-Type”, “application/json”);

 

if (modifiedPrompt != “”) {

openaiRequestBody.put(“prompt”, “You are a helpdesk agent named ” + agentName + “. Read the messages in this ticket:\n” + ticketConversation + “\n” + modifiedPrompt);

} else {

openaiRequestBody.put(“prompt”, “You are a helpdesk agent named ” + agentName + “. Read the messages in this ticket:\n” + ticketConversation + “\nCraft a professional response addressing the sender by name, but do not add a signature for yourself.”);

}

 

openaiRequestBody.put(“model”, “gpt-3.5-turbo”);

openaiRequestBody.put(“max_tokens”, 150);

 

// 5. Send data to OpenAI API to generate a new response

openaiURL = “https://api.openai.com/v1/completions”;

openaiResponse = postUrl(openaiURL, openaiRequestBody.toString(true), openaiHeaders);

if (openaiResponse.get(“status_code”) != 200) {

info “Error from OpenAI API: ” + openaiResponse;

return;

}

 

openaiChoices = openaiResponse.get(“choices”);

if (openaiChoices.isEmpty()) {

info “No valid response from OpenAI”;

return;

}

 

openaiResponseContent = openaiChoices.get(0).get(“text”);

 

// 6. Post the new generated response as a private message in Zoho Desk

replyMap = Map();

replyMap.put(“content”, openaiResponseContent);

replyMap.put(“isPublic”, false);  // Send as private message

 

zohoDeskReplyURL = “https://desk.zoho.com/api/v1/tickets/” + ticketId + “/comments”;

replyResponse = postUrl(zohoDeskReplyURL, replyMap.toString(true), headersMap);

 

if (replyResponse.get(“status_code”) != 200) {

info “Error posting reply: ” + replyResponse;

} else {

info “Reply posted successfully”;

}

 

Create a new macro for this function.

Image 4.1

Test it by running the macro on a ticket after modifying the comment from the previous function.

Image 4.2

How It Works:

  1. Fetching Comments: Retrieves all comments and identifies the latest private one.
  2. Extracting Modified Prompt: Looks for text between ## in the last private comment.
  • Preparing OpenAI Prompt: Uses the modified prompt if available; otherwise, defaults to the standard prompt.
  1. Generating Response: Calls OpenAI API with the prepared prompt.
  2. Posting Response: Adds the AI-generated reply as a new private comment.

 

Conclusion

By following these steps, you now have a fully functional AI-powered automation in Zoho Desk. You’ve learned to create progressively advanced custom functions using Deluge, integrate OpenAI’s API, and automate ticket replies through macros. This can be customized further based on your business requirements.

By following this guide, you’ve learned how to:

  • Authenticate with Zoho Desk API using OAuth 2.0.
  • Create custom functions in Zoho Desk to automate ticket replies.
  • Integrate OpenAI’s GPT models to generate professional responses.
  • Enhance functionality by allowing agents to adjust AI prompts for tailored replies.

These custom functions streamline the support process, saving time and ensuring consistent communication with customers. Feel free to build upon these examples to further customize your support workflow.

 

Disclaimer: Replace all placeholders like YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_ACCESS_TOKEN, and YOUR_OPENAI_API_KEY with your actual credentials. Always ensure that sensitive information is securely stored and not exposed in your code repositories.

Recent Posts
  • How to Create Macros to Automate Ticket Replies in Zoho Desk
  • Integrating Zoho Creator and Zoho Desk using a Widget Extension
  • A System Admin’s Guide to Securing Zoho One Using Active Directory (Part II)
  • A System Admin’s Guide to Setting Up Zoho One Using Active Directory (Part I)
Share This Post

Related Posts

Discover the latest news and updates on Zoho applications.

Unlock Your Knowledge Journey!

Get three articles for free, then enjoy unlimited access by registering.