Kaizen 232 - Building a Ticket Escalation Mechanism from Zoho CRM

Kaizen 232 - Building a Ticket Escalation Mechanism from Zoho CRM



Howdy, Tech Wizards!

Picking up the thread from last week, we will continue our Zoho CRM and Zoho Desk integration. 

In Kaizen #231 - Embedding Zoho Desk Tickets in Zoho CRM, we built a Related List widget that displays open Zoho Desk tickets within the Contact detail page. 

Now, let us take it a step further. 

We will enable sales representatives to escalate critical support tickets directly from Zoho CRM.

This controlled escalation mechanism triggers the SLA in Zoho Desk and simultaneously creates a trackable work item in Zoho CRM. The work item captures additional notes from the Sales team, enabling immediate action by the support team. It also allows Sales to monitor escalation progress anytime.

Business Problem

At Zylker, the Sales team works in Zoho CRM to manage customer relationships and track ongoing deals, while the Support team uses Zoho Desk to manage customer issues and service requests. Now the sales representatives have visibility into open support tickets using the widget built in the previous post. However, there is no structured way to escalate tickets from within Zoho CRM.

This leads to:
  1. Delayed escalations, increasing customer frustration.
  2. Lack of accountability when issues slip through the cracks.
  3. No audit trail of internal interventions for compliance and review.
Visibility alone is not enough. Sales teams need an actionable escalation mechanism within CRM.

Solution

We will extend the existing Related List widget by adding an Escalate button to each ticket row. On clicking this button, a confirmation pop-up appears. 

When the user clicks the Confirm button in the pop-up, the ticket status in Zoho Desk is updated to Escalation from Zoho CRM. This status change triggers the associated SLA configured in Zoho Desk.

As part of the SLA automation, the ticket priority can be updated to High, and the ticket owner can be notified. You can also configure additional actions based on your business requirements. If the Support team does not respond within the defined SLA time, the ticket can be automatically escalated to a manager or the escalation team.

After the ticket status is updated, the confirmation pop-up closes and an escalation form appears within the parent widget. This form allows the Sales team to capture additional details such as escalation reason, customer impact, and expected closure date. When the form is submitted, a record is created in a custom module called Escalation Work Items in Zoho CRM.

The Support team accesses only the Escalation Work Items module in Zoho CRM. This module acts as a shared escalation tracker between the Sales and Support teams. Support agents review the escalation details provided by Sales, take the required action in Zoho Desk, and update the escalation record in CRM. This allows the Sales team to track progress and stay informed before their sales call. 

Prerequisites

1. Complete the Related List Widget setup from Kaizen #231 - Embedding Zoho Desk Tickets in Zoho CRM. Ensure the following are already configured:
  1. Related List Widget in CRM
  2. Two-way sync between Zoho CRM and Zoho Desk
  3. Existing Zoho Desk connection
  4. Working widget project
2. Update the existing Zoho Desk connection to include the Desk.tickets.UPDATE scope in addition to the existing Desk.tickets.READ and Desk.contacts.READ scopes.


Refer to the Connections help doc for more information. 

3. Create a custom module named Escalation Work Items in Zoho CRM to store escalation records. 


  1. Go to Zoho CRM > Setup > Customization > Modules and Fields.
  2. Click Create New Module and enter Escalation Work Items as the module name. 
  3. Add the following custom fields:
Fields
Date Type
Contact Name
Lookup
Customer Impact
Multiline
Desk Ticket
URL
Escalation Reason
Multiline
Expected Closure Date
Date Time

Refer to the Customizing Modules help page to learn more about it. 


Make GET Modules Metadata and GET Fields Metadata API calls to retrieve the API names of the required module and its fields.

Store these API names, as they will be used later in the widget implementation.

4. Create a custom ticket status in Zoho Desk to differentiate that the particular ticket is escalated from Zoho CRM. 
  1. Log into Zoho Desk. 
  2. Go to Settings > Customization > Layouts and Fields > Ticket Status and click Add Status.
  3. Fill in the Status Name, Status Type and click Save.


4. Create an SLA in Zoho Desk that triggers when the ticket status changes to Escalation from Zoho CRM.
  1. Go to Settings > Automation > Service Level Agreements and click New SLA
  2. Provide Name and Description to the SLA. 
  3. Choose the trigger condition as Field Update and select the Status field. 
  4. Click Next and proceed configuring the target
  5. Configure the escalation rules, response times, and resolution targets as per your business requirements.


5. Create two new files called escalate-popup.html and escalate-popup.js in the widget project. These files will handle the confirmation dialog UI and button actions. 

This pop-up acts as a sub-widget of the parent Related List widget.

6. Validate and Pack the parent widget with the empty files and upload it to Zoho CRM to register the sub-widget. 
  1. Go to Zoho CRM > Setup > Developer Hub > Widgets and click Create New Widget
  2. Provide the widget details and choose the widget type as Button.
  3. Set the file path of escalate-popup.html as the Index Page and upload the package. 
  4. After saving the widget, navigate to the Widget Details page to find its API name. Store this API name, as it will be required in the parent widget to render the pop-up using the openPopup() method. 

Step-by-Step Implementation

In the existing widget project directory, we will add the escalation functionality.

Step - 1: Add the Escalate Button to the Ticket Table

In the renderTickets function, add an escalate button alongside the view link for each ticket row. On clicking, the button has to call the escalateTicket function that opens a pop-up. 

Step - 2: Create the Escalation Confirmation Pop-up

Add the HTML and CSS for the pop-up in the escalate-popup.html and the button functions in the escalate-popup.js file. 

ZOHO.embeddedApp.on("PageLoad", function(data) {
    console.log("Escalation popup loaded with data:", data);
});
ZOHO.embeddedApp.init();
// Confirm escalation - close popup and return confirmed: true
document.getElementById('confirmBtn').addEventListener('click', function() {
    $Client.close({ confirmed: true });
});
// Cancel escalation - close popup and return confirmed: false
document.getElementById('cancelBtn').addEventListener('click', function() {
    $Client.close({ confirmed: false });
});

Use the $Client.close() in pop-up to return data back to the parent widget. When the user clicks Confirm, it returns { confirmed: true }, and when they click Cancel, it returns { confirmed: false }.

Step - 3: Implement the Escalate Ticket Function

In the escalateTicket function, use the openPopup method to open the escalate-popup.html file and render the confirmation dialog. 

When the user clicks Confirm, call the Zoho Desk Update Ticket API to change the ticket status to Escalation from Zoho CRM. This status change automatically triggers the configured SLA in Zoho Desk.

// Escalate a ticket using openPopup
async function escalateTicket(ticketId, subject) {
    try {
        // Open the escalation confirmation popup widget
        var result = await ZDK.Client.openPopup({
            api_name: 'Zoho_Desk_Pop_Up',
            type: 'widget',
            animation_type: 6,
            header: 'Escalate Ticket',
            bottom: 'center',
            height: '250px',
            width: '400px'
        }, {
            ticketId: ticketId,
            subject: subject
        });
        console.log("Popup result:", result);
        // If user clicked Confirm
        if (result && result.confirmed) {
            ZDK.Client.showLoader('Escalating ticket...');
            // Update ticket status to "Escalation from Zoho CRM" using Desk Update Tickets API
            const updateResponse = await deskZrc.patch('/tickets/' + ticketId, {
                status: 'Escalation From Zoho CRM'
            });
            console.log("Update Ticket Response:", updateResponse);
            ZDK.Client.hideLoader();
            ZDK.Client.showMessage('Ticket escalated successfully');
            // Show escalation details form
            var ticketUrl = 'https://desk.zoho.com/agent/zylkerpvtltd/zylker/tickets/details/' + ticketId;
            renderEscalationForm(ticketId, ticketUrl, subject);
        }
    } catch (error) {
        ZDK.Client.hideLoader();
        console.error('Error escalating ticket:', error);
        ZDK.Client.showAlert('Failed to escalate the ticket. Please try again.', 'Error');
    }

After the ticket status is successfully updated, render an escalation form within the parent widget to capture additional details.

The form should pre-populate the ticket subject and ticket URL as read-only fields. It should also allow the user to enter the customer impact, escalation reason, and expected closure date.

Step - 4: Create an Escalation Entry in Zoho CRM

The Save button should trigger the saveEscalationRecord function. The function validates that all fields are filled and formats the datetime with timezone offset as required by Zoho CRM. The Contact_Name field relates the escalation record to the current Contact using the entityId captured during page load.

With this payload, the function creates a record in the Escalation Work Items module using the Insert Record API via the ZRC POST method

// Save escalation record to Zoho CRM
async function saveEscalationRecord(ticketUrl, ticketSubject) {
    var customerImpact = document.getElementById('customerImpact').value.trim();
    var escalationReason = document.getElementById('escalationReason').value.trim();
    var expectedClosureDate = document.getElementById('expectedClosureDate').value;
    if (!customerImpact || !escalationReason || !expectedClosureDate) {
        ZDK.Client.showAlert('Please fill in all fields before saving.', 'Validation Error');
        return;
    }
    // Format datetime with timezone offset for CRM 
    var dateObj = new Date(expectedClosureDate);
    var tzOffset = -dateObj.getTimezoneOffset();
    var tzSign = tzOffset >= 0 ? '+' : '-';
    var tzHours = String(Math.floor(Math.abs(tzOffset) / 60)).padStart(2, '0');
    var tzMins = String(Math.abs(tzOffset) % 60).padStart(2, '0');
    var closureDate = dateObj.getFullYear() + '-' +
        String(dateObj.getMonth() + 1).padStart(2, '0') + '-' +
        String(dateObj.getDate()).padStart(2, '0') + 'T' +
        String(dateObj.getHours()).padStart(2, '0') + ':' +
        String(dateObj.getMinutes()).padStart(2, '0') + ':' +
        String(dateObj.getSeconds()).padStart(2, '0') +
        tzSign + tzHours + ':' + tzMins;
    var recordData = [{
        "Name": ticketSubject,
        "Customer_Impact": customerImpact,
        "Escalation_Reason": escalationReason,
        "Expected_Closure_Date": closureDate,
        "Desk_Ticket": ticketUrl,
        "Contact_Name": { "id": entityId }
    }];
    try {
        ZDK.Client.showLoader('Saving escalation record...');
        const crmResponse = await zrc.post('/crm/v8/Escalation_Work_Items', {
            data: recordData
        });
        console.log("CRM Insert Response:", crmResponse);
        ZDK.Client.hideLoader();
        ZDK.Client.showMessage('Escalation record created successfully');
        // Go back to tickets list
        await loadTickets();
    } catch (error) {
        ZDK.Client.hideLoader();
        console.error('Error creating escalation record:', error);
        ZDK.Client.showAlert('Failed to create escalation record. Please try again.', 'Error');
    }
}

Step - 5: Validate and Pack the Widget

Follow the steps given in the Widget help page to validate and pack the widget. A complete working code sample is provided as attachment at the end of this post.

Step - 6: Update the Widgets in Zoho CRM

Since we have added new functionality to the widgets, we need to update it in Zoho CRM.
  1. Go to Zoho CRM > Setup > Developer Hub > Widgets.
  2. Locate the existing Related List widget and pop-up widget. 
  3. Click the settings icon and select Edit
  4. Update the package in both the widgets and click Save

Try it Out!

Let us look at the escalation flow from the Contacts detail page in Zoho CRM.



Info
Key Points to Remember
  1. The Desk connection must include Desk.tickets.UPDATE scope in addition to Desk.tickets.READ and Desk.contacts.READ scopes.
  2. The custom module API name Escalation_Work_Items and field API names like Customer_Impact, Escalation_Reason, Expected_Closure_Date, Desk_Ticket, and Contact_Name are organization-specific. Replace them with your actual API names in the saveEscalationRecord function.
  3. The pop-up widget must be registered separately in the Widgets page, and its API name must be used in the openPopup method. Update the api_name parameter in line 229 with your pop-up widget's API name.
  4. Update the Desk URL pattern in lines 182 and 266 with your portal name and company name.
  5. Ensure the SLA in Zoho Desk is configured to trigger when the status changes to Escalation from Zoho CRM.
  6. If you have a large number of contacts or tickets, implement pagination using from and limit parameters as mentioned in the previous Kaizen.
We hope this Kaizen empowers your sales team to take immediate action on critical support issues without leaving Zoho CRM. The combination of visibility and controlled escalation ensures that no customer issue falls through the cracks.

Have questions or suggestions? Drop them in the comments or write to us at support@zohocrm.com.

On to Better Building!

-----------------------------------------------------------------------------------------------------------

Related Reading 

2. Connections - An Overview
3. CRM Customizations - Related Lists
4. CRM APIs - Insert Records API

-----------------------------------------------------------------------------------------------------------
Idea
Previous Kaizen: Embedding Zoho Desk Tickets in Zoho CRM | Kaizen Collection: Directory